备战蓝桥杯————二分查找(二)

引言

        在上一篇博客中,我们深入探讨了二分搜索算法及其在寻找数组左侧边界的应用。二分搜索作为一种高效的查找方法,其核心思想在于通过不断缩小搜索范围来定位目标值。在本文中,我们将继续这一主题,不仅会回顾二分搜索的基本原理,还将重点介绍如何利用这一算法来寻找数组中目标值的右侧边界。通过对比左侧和右侧边界的搜索,我们将揭示二分搜索算法的灵活性和强大功能。无论您是在准备技术面试,还是在日常编程中寻求效率提升,本文都将为您提供宝贵的洞见。

一、寻找右侧边界的二分查找

        在有序数组中寻找特定值的右侧边界是二分查找算法的一个重要变体。与寻找左侧边界类似,我们可以通过调整搜索区间的边界来实现。本文将介绍两种写法:左闭右开的常见写法和两端都闭的统一写法。

基本代码

int right_bound(int[] nums, int target) {
    int left = 0, right = nums.length;
    
    while (left < right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] == target) {
            left = mid + 1; // 注意
        } else if (nums[mid] < target) {
            left = mid + 1;
        } else if (nums[mid] > target) {
            right = mid;
        }
    }
    return left - 1; // 注意
}

代码解释

1. 为什么这个算法能够找到右侧边界?

答:关键在于当 nums[mid] == target 时,我们不立即返回,而是通过 left = mid + 1 增大搜索区间的左边界,从而锁定右侧边界。

2. 为什么最后返回 left - 1 而不是 left

答:由于循环终止时 leftright 相等,而我们希望返回的是目标值的右侧边界,所以需要返回 left - 1。这样,当 left 等于数组长度时,表示目标值不存在,返回 -1

3. 如何处理目标值不存在的情况?

答:在循环结束后,我们检查 nums[left - 1] 是否等于目标值。如果不等于,或者 left - 1 索引越界,说明目标值不存在,返回 -1

二、在排序数组中查找元素的第一个跟最后一个

题目描述

        给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值 target,返回 [-1, -1]。你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。

示例 1:

输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]

示例 2:

输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]

示例 3:

输入:nums = [], target = 0
输出:[-1,-1]

提示:

  • 0 <= nums.length <= 105
  • -109 <= nums[i] <= 109
  • nums 是一个非递减数组
  • -109 <= target <= 109

代码实现及思路

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int left=0,right=nums.length-1;
        int[] arr = new int[2];
        if(nums.length==0)return new int[]{-1,-1};
        if(nums.length==1 && nums[0]==target)return new int[]{0,0};
        if(nums.length==1 && nums[0]!=target)return new int[]{-1,-1};
        while(left<=right){
            int mid=left+(right-left)/2;
            if(nums[mid]>=target)right=mid-1;
            if(nums[mid]<target)left=mid+1;
        }
        if(left<nums.length)arr[0]= nums[left]==target?  left:-1;
        else arr[0]=-1;
        right=nums.length-1;
        while(left<=right){
            int mid=left+(right-left)/2;
            if(nums[mid]<=target)left=mid+1;
            if(nums[mid]>target)right=mid-1;
        }
        if(right>=0)arr[1]= nums[right]==target? right:-1;
        else arr[1]=-1;
        return arr;
    }
}

        这段代码实现了一个名为 searchRange 的方法,它用于在一个有序数组 nums 中查找给定目标值 target 的第一个和最后一个出现的索引。该方法返回一个包含两个元素的数组,第一个元素是目标值的最小索引(左侧边界),第二个元素是最大索引(右侧边界)。如果目标值不存在于数组中,则两个元素都为 -1。

以下是该方法的思路:

1. 初始化变量:

  • left 和 right 分别初始化为数组的起始索引和结束索引。
  • arr 是一个长度为 2 的数组,用于存储目标值的左侧和右侧边界索引。

2. 处理特殊情况:

  • 如果数组长度为 0,直接返回 [-1, -1],因为空数组中不存在任何元素。
  • 如果数组长度为 1,检查数组中的唯一元素是否等于目标值。如果相等,返回 [0, 0];如果不相等,返回 [-1, -1]。

3. 寻找左侧边界:

  • 使用二分查找的变体来定位目标值的左侧边界。
  • 在 while 循环中,根据 nums[mid] 与 target 的比较结果,调整 left 或 right 的值。
  • 当 `left` 大于 right 时,循环结束,表示搜索区间为空,目标值不存在。
  • 在循环结束后,检查 left 是否在数组范围内,并且 nums[left] 是否等于目标值。如果是,arr[0] 赋值为 left,否则为 -1。

4. 重置变量并寻找右侧边界:

  • 将 right 初始化为数组的最后一个索引。
  • 再次使用二分查找的变体,但这次是为了找到目标值的右侧边界。
  • 调整 left 或 right 的值,使得 left 向右移动,right 向左移动,直到找到目标值的最后一个出现位置。
  • 在循环结束后,检查 right 是否在数组范围内,并且 nums[right] 是否等于目标值。如果是,arr[1] 赋值为 right,否则为 -1。

5. 返回结果:

  • 返回包含左侧和右侧边界索引的数组arr。
  • 这种方法确保了即使在目标值在数组中多次出现的情况下,也能正确地找到其首次和最后一次出现的索引。通过两次二分查找,分别从数组的两端向中间搜索,可以有效地定位目标值的边界。

结果展示

文末

        通过本文的讨论,我们不仅复习了二分搜索的基本概念,还学习了如何扩展这一算法来寻找数组中元素的左侧和右侧边界。这些技巧不仅在解决特定编程问题时非常有用,也体现了算法思维在优化问题解决过程中的重要性。二分搜索算法的变体和应用广泛,从简单的查找问题到复杂的数据结构操作,都可以看到它的身影。希望本文能够帮助您更好地理解和运用二分搜索,提升您的编程技能。感谢您的阅读,期待在下一篇文章中与您再次相遇

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/435090.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

leetcode 热题 100_最小覆盖子串

题解一&#xff1a; 双指针滑动窗口&#xff1a;暴力解法——用双指针来表示字符串s中的子串首尾&#xff0c;遍历所有子串并与字符串t判断是否符合条件。我们可以对遍历和判断的过程进行优化&#xff0c;首先是遍历&#xff0c;右指针先移动直到涵盖所以需要的字母&#xff0c…

弹性地基梁matlab有限元编程 | 双排桩支护结构 | Matlab源码 | 理论文本

专栏导读 作者简介&#xff1a;工学博士&#xff0c;高级工程师&#xff0c;专注于工业软件算法研究本文已收录于专栏&#xff1a;《有限元编程从入门到精通》本专栏旨在提供 1.以案例的形式讲解各类有限元问题的程序实现&#xff0c;并提供所有案例完整源码&#xff1b;2.单元…

记一次systemd服务启动找不到Java命令

首先systemd服务文件 /etc/systemd/system/test.service(文件简化处理了) [Unit] Descriptiontest Afternetwork.target [Service] ExecStart/opt/test/bin/test_start.sh [Install] WantedBymulti-user.target其中启动命令ExecStart指向的是一个sh启动脚本&#xff0c; 脚本内…

Zabbix(三)

监控Nginx服务 nginx配置 增加location{} [rootwenzi ~]#vim /etc/nginx/sites-enabled/defaultserver_name _; #_是通配符。服务器将响应任何域名的请求 ...location /status { stub_status;} ...访问 http://IP/status 即可 zabbix配置 Nginx by HTTP&#xff1a;无…

【重要公告】BSV区块链上线TypeScript SDK,未来将支持更多开发语言

​​发表时间&#xff1a;2024年2月21日 BSV区块链协会宣布上线JavaScript和TypeScript SDK&#xff08;即“标准开发工具包”&#xff09;。TypeScript SDK旨在为开发者提供新版统一核心代码库&#xff0c;以便利开发者在BSV区块链上开发能够任意扩容的应用程序。新上线的SDK替…

目标检测评估指标

目录 一、检测精度1、TP、FP、TN、FN概念正样本和负样本TP(True Positive---正确的正向预测)FP(False Positive---错误的正向预测&#xff09;FN(False Negative---错误的负向预测)TN(True Negative---正确的负向预测) 2、Precision(准确率)和Recall(召回率)3、P-R curve &…

C++STL【list链表】

list 1. list介绍 list文档&#xff08;非官方&#xff09; 官方文档list是双向带头循环链表&#xff0c;它可以在常数范围内的任意位置进行插入和删除操作。list的迭代器是双向迭代器(bidirectional iterator)&#xff0c;它可以前后双向迭代。 由容器的底层结构决定&#xf…

SQOOP安装与使用

SQOOP安装及使用 文章目录 SQOOP安装及使用SQOOP安装1、上传并解压2、修改配置文件3、修改环境变量4、添加MySQL连接驱动5、测试 准备MySQL数据登录MySQL数据库创建student数据库切换数据库并导入数据另外一种导入数据的方式使用Navicat运行SQL文件导出MySQL数据库 importMySQL…

HarmonyOS应用开发-环境搭建(windows环境)

官网地址&#xff1a;链接 DevEco Studio 3.1.1 Release&#xff1a;下载地址 1、安装DevEco Studio 直接安装即可 2、配置开发环境 1.运行已安装的DevEco Studio&#xff0c;首次使用&#xff0c;请选择Do not import settings&#xff0c;单击OK。 2.安装Node.js与ohpm。注…

【MySQL】索引优化与关联查询优化

数据库调优的几个维度&#xff1a; 索引失效&#xff0c;没有充分用到索引——索引建立关联查询太多JOIN——SQL优化服务器调优以及各个参数设置——调整my.cnf数据过多——分库分表 SQL查询优化的几种方式&#xff1a; 物理查询优化&#xff1a;通过索引以及表连接方式进行…

微服务分布式中为什么要分库分表呢?

什么是分库分表&#xff1f; 概念&#xff1a; 分库分表是一种数据库水平扩展的方法&#xff0c;通过将数据分散存储在多个数据库实例或多张表中&#xff0c;以提高系统的性能和扩展性。在Java应用中&#xff0c;可以使用一些数据库中间件或框架来实现分库分表。 为什么要分…

2024-3-6-数据库作业

作业&#xff1a;数据库操作的增、删、改完成 源代码&#xff1a; #include <myhead.h> void do_add(sqlite3 *ppDb) {char *errmsg NULL;char sql[128] "insert into Worker values(1001,小张,15000);";// "insert into Worker values(1002,小刘,900…

实验一 将调试集成到vscode

先唤起终端&#xff0c;按照上一篇文章的步骤分别启动调试服务器和调试客户端&#xff0c;然后挂在后台 PS&#xff1a;同时挂两个终端可以开两个窗口&#xff0c;也可以使用多窗口分屏式终端terminator 注意是要图二的光标一直闪&#xff0c;如果熄灭了说明连接超时了&#xf…

Linux中systemv共享内存

目录 1.原理 2.接口 1.shmget(share_memory_get获得共享内存) 2.ftok 3.shmat(share_memory_attaintion挂接到物理内存上) 4.key和shmid的区别 5.ipc 指令 6.shmdt函数&#xff08;share_memory_detach取消挂接&#xff09; 7.shmctl函数&#xff08;share_memory_cont…

【你也能从零基础学会网站开发】Web建站之HTML+CSS入门篇 网站开发的基本概念与站点文件的管理

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;web开发者、设计师、技术分享 &#x1f40b; 希望大家多多支持, 我们一起学习和进步&#xff01;&#x1f604; &#x1f3c5; 如果对你有帮助的话&#xff0c;欢迎评论 &#x1f4ac;点赞&#x1f44d;&…

笔记本上使用usb蓝牙适配器

注意 必须先禁用笔记本上原来的蓝牙功能 禁用笔记本原来的蓝牙功能 使用usb蓝牙适配器

matlab读取hdf5格式的全球火灾排放数据库Global Fire Emissions Database(GFED)数据

1.引言 火灾是大气中痕量气体和气溶胶的重要来源&#xff0c;并且是全球尺度上最重要的干扰因素。此外&#xff0c;森林砍伐和热带泥炭地火灾以及火灾频率增加的地区&#xff0c;都会增加大气中二氧化碳的积累。烧毁面积提供了生物质燃烧事件期间受火灾影响土地的估算&#xff…

实时智能应答数字人搭建

语音驱动口型的算法 先看效果&#xff1a; 你很快就可以帮得上我了 FACEGOOD 决定将语音驱动口型的算法技术正式开源&#xff0c;这是 AI 虚拟数字人的核心算法&#xff0c;技术开源后将大程度降低 AI 数字人的开发门槛。FACEGOOD是一家国际领先的3D基础软件开发商&#xff0c;…

分类算法(Classification algorithms)

逻辑回归(logical regression&#xff09;&#xff1a; 逻辑回归这个名字听上去好像应该是回归算法的&#xff0c;但其实这个名字只是在历史上取名有点区别&#xff0c;但实际上它是一个完全属于是分类算法的。 我们为什么要学习它呢&#xff1f;在用我们的线性回归时会遇到一…

Xss-labs-master 1-16关

第一关 <?php ini_set("display_errors", 0); $str $_GET["name"]; echo "<h2 aligncenter>欢迎用户".$str."</h2>"; ?> <center><img srclevel1.png></center> <?php echo "&l…