coding ability 展开第五幕(二分查找算法)超详细!!!!

embedded/2025/3/29 1:47:54/

.在这里插入图片描述

.

文章目录

  • 前言
  • 二分查找
  • 搜索插入的位置
    • 思路
  • x的平方根
    • 思路
  • 山脉数组的峰顶索引
    • 思路
  • 寻找旋转排序数组中的最小值
    • 思路
  • 总结

前言

本专栏上篇博客已经把滑动指针收尾啦
现在还是想到核心——一段连续的区间,有时候加上哈希表用起来很爽
今天我们来学习新的算法知识——二分查找,相信大家都不陌生
二分查找,怎么说呢,清晰了解之后,其实代码就几行
话不多说,跟我一起来瞅瞅吧

二分查找

首先我们来学习两道经典例题,有了例题和板子,才能更好的扩展和延伸,应对不同的场景
二分查找
在这里插入图片描述
其实乍一看,直接遍历一遍不就好了吗,但是今天我们的主题是二分查找
所以这一题来学习一下二分的第一个最简单的板子
解法一就是暴力循环找目标值
解法二:
在这里插入图片描述
其实核心就是二段性,只要给的数据有二段性,我们就能用二分
最朴素的就是不断的找 mid 然后判断 ,再进到新的区间 ,不断二分
看看这题代码,其实大家应该都会写的,最基础的二分板子

class Solution 
{
public:int search(vector<int>& nums, int target){int left = 0, right = nums.size() - 1;while(left <= right){int mid = left + (right - left) / 2;if(target > nums[mid])left = mid + 1;else if( target < nums[mid])right = mid - 1;elsereturn mid;}return -1;}
};

可能觉得二分就这么简单吗?? 不不不,还有另外两个板子,会有点麻烦
在排序数组中查找元素的第一个和最后一个位置
在这里插入图片描述
这题能把另外两个二分的板子完美诠释出来,在做这一题之前,我们先来了解两种情况
前面我们的朴素版本就是 大于 等于 小于 三种情况。
现在我们来想想 左边区间是小于目标值 右边区间是大于等于目标值 两种情况怎么处理
也就是找区间的左端点,如下图:
在这里插入图片描述
相比于前面的朴素板子,有很多细节差别
—left 和 right 的更新, 当 x 小于目标值时,那就是左边区间,这时候left——mid的区间都是不满足条件的,因为左边区间都是小于目标值,所以 left 要更新为 mid+1当 x 大于等于目标值时,因为我们右边区间默认是大于等于目标值的区间,我们的 right 如果更新为 mid - 1,有可能当前的mid就是要找寻的点所以 right 应该更新为 mid
—循环条件 当 left == right 时,就是我们要找的答案,这个时候如果循环条件为 left<=right ,会进入死循环
mid的取值,看下图,假设就剩下两个值,目标值是left先用第一种方法 mid 就是 left,这个时候 x >= 目标值所以right == mid刚好left 和 right 相等,找到目标值,如果取用第二种方法取mid为right,这个时候 x >= 目标值,right 和 mid 相等,然后left还是小于right,死循环,所以当我们把区间分成左边完全小于目标值,右边大于等于目标值的时候,就用第一种
在这里插入图片描述
左端点结束了,接下来就是右端点了
也就是左边区间小于等于目标值,右边区间完全大于目标值
在这里插入图片描述
需要注意的细节还是
—left 和 right 的更新 ,当 x > 目标值的时候 right更新为 mid - 1,因为右边区间都是大于目标值的, 当 x <= 目标值的时候left更新为mid,因为左边区间小于等于目标值,可能mid的位置就是目标值
—left < right left 不能等于 right
—还是 mid 的取值问题,再来回到这个图在这里插入图片描述
我们先使用第一种,当right为目标值时,更新 mid 是刚好为 left,这个时候left更新为mid,right还是大于left,陷入死循环,使用第二种的话,更新mid为rightleft更新为mid也就是right,left和right相等,跳出循环,找到目标值。所以当区间分成左区间小于等于,右区间大于时,用第二种取mid

好了,找左右端点我们都学会了这题,也是能稳稳拿下了
题目要求找到目标值的左右端点,那我们来一次找左端点的操作,再来一次右端点的操作就好啦,话不多说,上代码

class Solution 
{
public:vector<int> searchRange(vector<int>& nums, int target) {if(nums.size() == 0)return{-1, -1};int begin = 0;int left = 0, right = nums.size() - 1;while(left < right)   //  找左端点{int mid = left + (right - left) / 2;if(nums[mid] < target)left = mid + 1;elseright = mid;}if(nums[left] != target) return {-1, -1};begin = left;right = nums.size() - 1;while(left < right)  //  找右端点{int mid = left + (right - left + 1) / 2;if(nums[mid] > target)right = mid - 1;elseleft = mid;}return {begin, right};}
};

leetcode.cn/problems/search-insert-position/" rel="nofollow">搜索插入的位置

在这里插入图片描述

思路

这题看来就是左区间小于,又区间大于等于,二段性就分好啦
假设插入的坐标是x,那么x左边都是小于目标值的,右区间都是大于等于目标值的
我们可以用查询左端点的板子,直接返回找到的左端点
还有一种特殊情况就是,数据插入在末尾,原本的数据全部小于目标值的,就把这一点处理一下就好了
话不多说,上代码

class Solution 
{
public:int searchInsert(vector<int>& nums, int target) {int left = 0, right = nums.size() - 1;while(left < right){int mid = left + (right - left) / 2;if(nums[mid] < target)  //  特殊情况,所有数据都比目标值小left = mid + 1;		//	返回right + 1elseright = mid;}if(nums[left] < target)return left + 1;elsereturn right;} 
};

leetcode.cn/problems/sqrtx/" rel="nofollow">x的平方根

在这里插入图片描述

思路

本题第一种思路就是暴力枚举就好了,0-x/2区间一个一个枚举,挺简单的思路,就不多赘述了
第二种思路就是二分,我们可以用右端点的板子,设定 i * i <= x为条件,进行二分,最终返回的就是小于等于算数平方根的下标, 话不多说,上代码

class Solution 
{
public:int mySqrt(int x) {if(x == 0)return 0;long long right = x / 2, left = 1;while(left < right){long long  mid = left + (right - left + 1) / 2; // 查询右端点取中点处理if(mid * mid > (long long)x)right = mid - 1;elseleft = mid;}return left;        }
};

其实核心就是找到数据的二段性,然后看情况选择二分查找左端点还是右端点就好啦

leetcode.cn/problems/peak-index-in-a-mountain-array/" rel="nofollow">山脉数组的峰顶索引

在这里插入图片描述

思路

题目的意思是找到山脉的顶峰,第一种思路当然就是暴力查找了,找到最大值就行
第二种思路就是我们可以把山脉分成两份,二段性不就来了嘛,一段单调增,一段单调减
然后根据情况查找左端点或者右端点就好啦
我们把左区间设定为递增到山顶的区间,右区间就是下山的区间
这个时候应该用我们的查询右端点的板子,然后我们的判断条件可以设为 arr[mid] > arr[mid - 1]
话不多说,看代码

class Solution 
{
public:int peakIndexInMountainArray(vector<int>& arr) {int left = 1, right = arr.size() - 2;while(left < right){int mid = left + (right - left + 1) / 2;if(arr[mid] > arr[mid - 1]) left = mid;elseright = mid - 1;}return left;}
};

当然,也可以用查询左端点的板子来写

class Solution 
{
public:int peakIndexInMountainArray(vector<int>& arr) {int left = 1, right = arr.size() - 2;while(left < right){int mid = left + (right - left) / 2;if(arr[mid] > arr[mid + 1]) right = mid;elseleft = mid + 1;}return left;}
};

其实,核心就是找到二段性,然后再找判断条件

leetcode.cn/problems/find-minimum-in-rotated-sorted-array/" rel="nofollow">寻找旋转排序数组中的最小值

在这里插入图片描述

思路

题目的二段性意思已经写在脸上了,如图
在这里插入图片描述
我们直接设定右端点为 x ,然后上查找左端点的板子,这个x用来判断区间条件
就是两步,二段性,区间条件,话不多说,上代码

class Solution 
{
public:int findMin(vector<int>& nums) {int left = 0, right = nums.size() - 1;int x = nums[right];while(left < right){int mid = left + (right - left) / 2;if(nums[mid] > x) //  当前值大于  x  表示在左区间left = mid + 1;   //  更新leftelseright = mid;}return nums[left];}
};

总结

二分查找是一种高效的搜索算法,核心在于利用数据的二段性将区间不断二分,快速定位目标。本文通过经典例题解析了三种常见场景的二分应用:

  1. 基本查找:适用于有序数组,通过比较中间值与目标调整区间,时间复杂度O(logN)。
  2. 边界查找
    • 左边界:右区间≥目标,循环条件left<right,mid取左中点,更新策略确保不遗漏可能解。
    • 右边界:左区间≤目标,mid取右中点,避免死循环。
  3. 特殊场景:如山脉数组峰值、旋转数组最小值,通过分析数据规律(如单调性变化点)构造二段性条件。

关键点

  • 循环条件选择(left<rightleft<=right)。
  • mid计算方式(防止溢出)与边界更新策略。
  • 处理目标不存在或越界的特殊情况。

掌握二分查找的核心在于理解区间划分逻辑,灵活选择模板,结合问题特点设计判断条件,从而高效解决复杂查找问题

今天的内容就到这里啦,不要走开小编持续更新中~~~

在这里插入图片描述


http://www.ppmy.cn/embedded/176762.html

相关文章

000-JMeter简介

JMeter 是一个开源的性能测试工具&#xff0c;由 Apache 软件基金会开发&#xff0c;主要用于测试应用程序、服务和服务器的性能。它最初是为 Web 应用程序设计的&#xff0c;但现在已经扩展到支持多种协议和技术&#xff0c;如 HTTP、HTTPS、FTP、JDBC、SOAP、REST、JMS、TCP …

雷军从 6 楼扔涂有防弹涂层西瓜,西瓜完好无损,这种防弹涂层是什么材质?用在车上效果怎么样?

雷军展示的“防弹涂层”是一种基于第四代高分子材料聚脲&#xff08;Polyurea&#xff09;的升级技术&#xff0c;其核心特性是通过纳米级交联结构形成弹性防护层&#xff0c;兼具柔韧性与刚性&#xff0c;能够有效吸收冲击能量并抵御尖锐物体的穿刺。以下是关于该涂层材质及在…

ideaIU-2023.2.5.exe install (IntelliJ_IDEA_IU_2023.2.5)

ideaIU-2023.2.5.exe install &#xff08;IntelliJ_IDEA_IU_2023.2.5&#xff09;开发工具安装 所以注册失败了上面。 执行第①个脚本 执行第②个脚本

HTTP代理的全面解读:什么是HTTP代理?HTTP代理的工作原理

在互联网大潮中&#xff0c;每一个请求和返回数据的背后&#xff0c;都离不开传输协议的支持&#xff0c;而HTTP协议无疑是最熟悉的网络通信基础之一。当我们谈到HTTP代理时&#xff0c;它不仅让浏览网络变得更高效&#xff0c;也为数据采集以及全球性远程任务提供了解决方案。…

英语+C语言:3.24

一、8.3&#xff1a;结构体指针与typedef的应用 二、8.4&#xff1a;C引用 引用修改指针变量&#xff1a; 注意&#xff1a;引用必须与变量名紧挨着。 改为纯C语言的二级指针如下&#xff1a; 三、8.5&#xff1a;C引用案例实战 结构体的存储与其他变量相同&#xff0c;若是…

目标检测20年(二)

没有看过&#xff08;一&#xff09;的可以看看笔者这篇文章&#xff1a; 目标检测20年&#xff08;一&#xff09;-CSDN博客 目录 3.2 目标检测数据集和指标 3.2.1 数据集 3.2.1.1 Pascal VOC 3.2.1.2 ILSVRC 3.2.1.3 MS-COCO 3.2.1..4 Open Images 3.2.2 指标 3.3 目…

Qt中10倍提升动态截屏及渲染60帧/秒

Qt中10倍提升动态截屏及渲染60帧/秒 理解模态窗口和非模态窗口 在C中&#xff0c;窗口的**模态&#xff08;Modal&#xff09;和非模态&#xff08;Modeless&#xff09;**显示是两种不同的对话框或窗口行为模式&#xff0c;主要区别体现在用户交互和程序流程控制上。以下是它…

【计算机网络】网络简介

文章目录 1. 局域网与广域网1.1 局域网1.2 广域网 2. 路由器和交换机3. 五元组3.1 IP和端口3.2 协议3.3 协议分层 4. OSI七层网络协议5. TCP/IP五层模型5.1 TCP/IP模型介绍5.2 网络设备所在分层 6. 封装与分用6.1 数据包的称谓6.2 封装6.3 分用 1. 局域网与广域网 1.1 局域网 …