二分查找算法例题(二)

寻找峰值

题目要求:

题目要求:

从一个山峰数组中,寻找并返回一个"峰值元素"(严格大于左右的元素),可能含有多个峰值元素,只用返回一个峰值元素即可。

题目解析以及核心思路:

题目解析:

根据题目特性分析可知"二段性":

  • arri>arri+1时,数组正处于下降趋势,说明之前一定有**"上升趋势",右侧部分数组** 不一定有峰值(不一定会再上升),则去左侧数组部分 寻找峰值
  • arri<arri+1时,数组正处于上升趋势,说明之后一定会出现**"峰值",左侧部分** 不一定已经经历一轮"上升下降",则去右侧数组部分 寻找峰值
    核心思路:

通过mid下标 来实现arri与arri+1的关系

  • arrmid>arrmid+1,去左侧数组部分,寻找峰值
  • arrmid<arrmid+1,去右侧数组部分,寻找峰值

代码实例:

java 复制代码
class Solution {
    public int findPeakElement(int[] nums) {
        int left=0;
        int right=nums.length-1;
        while(left<right){
            int mid=left+(right-left)/2;
            if(nums[mid]<nums[mid+1]){
                left=mid+1;
            }
            if(nums[mid]>nums[mid+1]){
                right=mid;
            }
        }
        return left;
    }
}

总结:

通过利用**"山峰"的特性,寻找"二段性"。** 即使是两个值之间的关系,也能根据其他特性推出"二段性",将数组一分为二

寻找旋转排序数组中最小值

题目要求:

题目要求:一个"元素互不相同,升序数组"进行旋转操作(即元素后移,位置不足则到最前)。多次旋转后,找最小元素。

题目解析以及核心思路:

题目解析:

可以知道,我们这个数组在多次旋转后一定会有这样的趋势

这样我们只要寻找到C点,就找到了整个数组的最小元素

二段性:选取一个点numsi与最后一个元素比较(最后一个元素一定在CD区间)

  • numsi>numsn-1:则当前在区间A-B中,需要向C-D区间去移动

  • numsi<=numsn-1:则当前在区间C-D中,需要向C-D区中的C点区移动


    补充: 如果数组旋转之后还是原本的样子呢?

  • 那么选取的numsi会一直存在于C-D 区间中最终会一直移动到A点(这种情况下最小)

核心思路:

  • 在A-B区间:numsmid>numsn-1-->left=mid+1
  • 在C-D区间:numsmid<=numsn-1-->right=mid

代码实例:

java 复制代码
class Solution {
    public int findMin(int[] nums) {
     int left=0;
     int right=nums.length-1;
     int n=nums.length;
     while(left<right){
        int mid=left+(right-left)/2;
        if(nums[mid]>nums[n-1]){
            //在AB段,要向CD段移动
            left=mid+1;
        }
        else{
            //在CD段,要尽量去找C点
            right=mid;
        }
     }
     return nums[left];   
    }
}

总结:

利用数组中条件:"原升序 "+"无重复元素"==>一定存在二段性,两段数组,从而使用二分查找算法

寻找0~n-1中缺失的数字

题目要求:

题目要求: 一个长为n-1 的数组递增排序,数组中缺少一个元素(本应是0~n),返回"缺失的元素"。

题目解析以及核心思路:

题目解析:

根据题目特征,我们分析这个数组的特性,就能得到独特的"二段性":"左区间数组'数组下标=='指向数组元素',右区间数组'数组下标'!='指向数组元素''"。


补充:本题其实还有其他多种写法,但由于时间复杂度都是O(n),稍逊于二分查找算法,因此,我们只在这里进行思路叙述,不提供具体代码,有兴趣大家可以自行尝试:

1.哈希表 :通过"键值对",键存储**"从0~n的数",值则通过遍历整个数组->有这个数,则对应键的值"+1",**最后,值为0的键中存储的数,就是目标数

**2.直接遍历找结果:**直接遍历数组一遍:若缺少中间数则直接得出结果;若缺少尾数,添上即可

3.高斯求和法: 先利用"高斯求和公式"求出**0~n的数的总和,**再遍历相加整个数组,两者相减得到的差,就是目标值
核心思路:

通过**"下标与值的相等关系"构成的"二段性"我们进行二分查找:**

  • 指向值与下标相同: 当前值处在左半区间 ,需要向右半区间移动
  • 指向值与下标不同: 当前值处在右半区间 ,需要在本区间内查找到"最左端点"(第一个开始偏离"下标"的值)

代码实例:

java 复制代码
class Solution {
    public int takeAttendance(int[] records) {
        //使用二分查找
        int left=0;
        int right=records.length-1;
        int n=records.length;
        while(left<right){
            int mid=left+(right-left)/2;
            //如果在左区间,则向右区间去查找
            if(records[mid]==mid){
                left=mid+1;
            }
            //如果在右区间,则向右区间的左端点去查找
            if(records[mid]!=mid){
                right=mid;
            }
        }
        //如果是末尾缺失的情况,此时不存在右区间
        if(left==n-1&&left==records[left]){
            return (left+1);
        }
        return left;
    }
}

总结:

本题通过"递增排序"+"连续的数"两个特性,得到"下标值与指向值应该相同"这一特点。由此推出**"下标值与指向值相等关系"的"二段性",**从而在O(logn)的时间复杂度解决了问题

关于二分查找算法的题目,我们就更新到这里,相信通过6道例题,大家应理解了二分查找使用的关键是**"寻找二段性",**希望这一思路能在未来帮助到大家,感谢大家的阅读

相关推荐
拳里剑气2 小时前
C++算法:多源BFS
c++·算法·宽度优先·多源bfs
ysa0510303 小时前
【板子】短序列dp(换成维护更小常数维度的dp)
c++·笔记·算法·板子
shwill1233 小时前
PID 算法(三)--- 增量 PID ↔ 单神经元 PID 等价映射
linux·算法
wabs6664 小时前
关于图论【卡码网110.字符串迁移的思考】
数据结构·算法·图论
hanlin035 小时前
刷题笔记:力扣第242、349题(哈希表)
笔记·算法·leetcode
only-qi6 小时前
大模型Agent面试攻略:落地工程痛点、评估体系与Agentic RAG核心精讲
人工智能·算法·面试·职场和发展·langchain·rag
Gauss松鼠会8 小时前
【GaussDB】GaussDB锁阻塞源头查询
java·开发语言·前端·数据库·算法·gaussdb·经验总结
oier_Asad.Chen8 小时前
【洛谷题解/AcWing题解】洛谷P4011 孤岛营救问题/AcWing1131拯救大兵瑞恩
数据结构·笔记·学习·算法·动态规划·图论·宽度优先
逻辑君8 小时前
基于 A2C 算法的双足机器人行走控制
人工智能·深度学习·算法·机器学习·机器人