简介
二分查找计算区间中点是否满足条件,从而划分需要查找的区间。当题目具有单调性特征时,二分查找可以O(logn)的时间复杂度解决问题。在计算区间中点时,一般有两种计算方法:
mid = (left + right + 1) / 2; // 方法一
mid = (left + right ) / 2; // 方法二
什么时候需要+1,什么时候不需要,是困扰许多初学者的问题,这篇博客做一个简单的分析,帮助初学者理解记忆。
二分查找分类
二分查找分为两类:
- 在[left, right]中,若mid不满足条件,则解落在左侧区间,则下一次寻找的区间是[mid, right]或[left, mid - 1]。
- 在[left, right]中,若mid不满足条件,则解落在右侧区间,则下一次寻找的区间是[mid + 1, right]或[left, mid]。
产生这两种分类的原因是:当mid不满足条件时,下一次求解,不需要将mid放进新的区间。因此,当新区间在左侧时,right移动到mid - 1,反之left移动到mid+1。
如何决定mid
我们+1的目的,是防止死循环。而会产生死循环的原因,则是当区间只有两个元素,即left和right中间没有其他元素时,更新left或right指针后,left或right指针原地不动。
产生这原地不动的原因,是因为只有两个元素时,mid要么落在left,要么落在right。以mid落在left为例,若此时我们是第一类二分查找,新区间是[mid. right],则left指针没有改变,因而就产生了死循环。
当区间只有两个元素时,计算mid时+1,则mid会落在right,反之会落在left。因此,根据你的二分查找类型,就可以判断需不需要+1。
一句话概括
当你更新left时,left = mid,那么你需要mid = (left + right + 1) / 2。
完整模版
// mid = (left + right) / 2
int binarySearch(vector<int>& nums, int left, int right){
while(left < right){
int mid = (left + right) >> 1;
if(isSolution(mid)){
right = mid;
}else{
left = mid + 1;
}
}
return left;
}
// mid = (left + right + 1) / 2
int binarySearch(vector<int>& nums, int left, int right){
while(left < right){
int mid = (left + right + 1) >> 1;
if(isSolution(mid)){
left = mid;
}else{
right = mid - 1;
}
}
return left;
}