寻找峰值
题目要求:

题目要求:
从一个山峰数组中,寻找并返回一个"峰值元素"(严格大于左右的元素),可能含有多个峰值元素,只用返回一个峰值元素即可。
题目解析以及核心思路:
题目解析:
根据题目特性分析可知"二段性":
- 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道例题,大家应理解了二分查找使用的关键是**"寻找二段性",**希望这一思路能在未来帮助到大家,感谢大家的阅读





