二分法的边界问题讨论
题目链接:
704. 二分查找
二分法虽然逻辑比较简单,但涉及到边界条件,容易写错。
处理思路:确定要二分的区间是[left, right]还是[left, right),然后在while循环中根据确定的区间来改变循环条件。
##二分写法(一)
定义区间target在区间[left, right]内,有如下两点:
- 因为left与right相等的情况在[left, right]区间是有意义的,所以循环条件应该是while(left <= right)
- 如果nums[mid]大于target,则更新搜索区间上界right为mid-1.因为当前这个nums[mid]一定不是target
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
//定义target在左闭右闭区间,即[left, right]
int right = nums.size() - 1;
//left==right时,此时区间仍有效
while (left <= right){
//防止溢出,等同于(left + right) / 2
int mid = left + ((right - left) >> 1);
if (nums[mid] == target) return mid; //找到target,返回下标
else if (nums[mid] > target) right = mid - 1; //target在左区间[left, mid - 1]
else left = mid+1;//target在右区间[mid+1, right]
}
//未找到目标值
return -1;
}
};
##二分写法(二)
定义target在区间[left, right),有如下两点:
- left与right相等的情况在区间[left, right)中是没有意义的,所以循环条件应为while(left<right)
- 如果nums[mid]大于target,则更新搜索范围的上界right为mid。因为下一个搜索区间是[left, mid),所以nums[mid]并不会被比较
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
//定义target在左闭右开区间,即[left, right)
int right = nums.size();
//left==right时,区间无效
while (left < right){
//防止溢出,等同于(left + right) / 2
int mid = left + ((right - left) >> 1);
if (nums[mid] == target) return mid; //找到target,返回下标
else if (nums[mid] > target) right = mid; //target在左区间[left, mid)
else left = mid+1;//target在右区间[mid+1, right)
}
//未找到目标值
return -1;
}
};