关于二分查找的理解
在leetcode_35搜索插入的位置
这道题中,liweiwei大佬详细的介绍了二分查找最关键的一个问题,就是如何避免陷入死循环。在此我根据大佬的笔记,总结一下自己的理解。
首先来看题目:
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
你可以假设数组中无重复元素。
输入: [1,3,5,6], 5
输出: 2
正常的解法如下:
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int size = nums.size();
if (size == 0) {
return 0;
}
// 特判
if (nums[size - 1] < target) {
return size;
}
int left = 0;
int right = size - 1;
while (left < right) {
// int mid = left + (right - left + 1)/2;//右中位数
int mid = left + (right-left)/2; //左中位数
if (nums[mid] < target) {
left = mid + 1;
}
else if (nums[mid] == target) {
return mid;
}
else {
right = mid;
}
}
return left;
}
};
这道题目的重点在与 左右区间的如何划分,这个地方如何理解呢?
正如二分法所要求的mid
,当求得mid
,之后,根据mid
的值和目标值进行比较,会存在区间的划分的两种情况:
-
情况1:
[left,mid]
和[mid+1,right]
-
情况2:
[left,mid-1]
和[mid,right]
但是mid
的值怎么计算呢?这个地方有两个需要注意的点!
注意点1:如何防止溢出
正常对于mid
的计算我们都是:
int mid = (left+right)/2;
这种情况下,当数组很长的时候,两个数直接相加就可能溢出。
所以一种比较好的习惯是:
int mid = left + (right-left)/2;
注意点2:mid
值是上取整还是下取整?
假设我们最后剩下的搜索区间是[2,3],那么因为int向下取整的原因,用注意点1里的方法,mid的值就是2;
如果是下取整,那么会存在什么情况呢?
我们分别代入区间划分的两种情况下进行测试:
-
情况1:
int mid = 2; //判断1:此时right=mid [left,mid] = [2,2] //判断2:left=mid+1 [mid+1,right] = [3,3]
没什么问题.
return left!
-
情况2:
int mid = 2; //判断1:此时right=mid-1 [left,mid-1] = [2,1] //判断2:left=mid [mid,right] = [2,3] //陷入死循环!!!
在判断1的情况下明显出错了!区间都划分的不对了。或者出现 死循环!
如果我们使用的是上取整呢?
也就是这样:
int mid = left + (right-left+1)/2;
再次分别代入以下区间划分的情况下进行测试:
-
情况1:
int mid = 3; //判断1:此时right=mid [left,mid] = [2,3]//陷入死循环!!! //判断2:left=mid+1 [mid+1,right] = [4,3]//区间不对了!!!
出现错误!不是陷入
死循环
,就是区间判断错误!不知道该如何退出! -
情况2:
int mid = 3; //判断1:此时right=mid-1 [left,mid-1] = [2,2] //判断2:left=mid [mid,right] = [3,3]
这种情况下安全退出!
所以这就是大佬说的,当遇到left = mid
的时候,才需要调整为上取整!!!!
相似的练习题!