二分搜索算法
基本的二分查找框架
- 简单查找,找到目标值在数组中的位置下标,如果没有则返回-1
int binarySearch(vector<int>& nums, int target){
int left = 0, r = nums.size() - 1;
while(left <= right){
int mid = left + (right - left) / 2;
if(target == nums[mid] ){
return mid;
}else if(target > nums[mid]){
left = mid + 1;
} else{
right = mid - 1;
}
}
return -1;
}
注意点:
while(left <= right)
中是"<“还是”<="号取决于right的取值,因为上述模板中的right取值为nums.size()-1
,即搜索区间为闭区间[left, right]
。对应的left = mid + 1
和right = mid - 1
中应该有+1
和-1
的操作。- 反之,如果取
right = nums.size()
,则表示为左闭右开的区间[left, right)
,所以while
循环中应该是while(left < right>
,不能取相等。当改变搜索空间时对应的应该为:left = mid + 1
和right = mid
。因为在上一次的搜索中,开区间right的值并未取到,而左边闭区间的left
是已经被遍历计算过,所以left = mid + 1
.
寻找左侧边界的二分搜索
- 上述方法存在缺陷
比如说给你有序数组nums = [1,2,2,2,3]
,target为 2
,此算法返回的索引是 2,没错。但是如果我想得到target的左侧边界
,即索引 1
,或者我想得到target的右侧边界
,即索引 3
,这样的话此算法是无法处理的。
int binarySearch(vector<int>& nums, int target){
int left = 0, r = nums.size() - 1;
while(left <= right){
int mid = left + (right - left) / 2;
if(target == nums[mid] ){
right = mid - 1;
}else if(target < nums[mid]){
right = mid - 1;
} else{
left = mid + 1;
}
}
if(left >= nums.size() || nums[left] != target)
return -1;
return left;
}
寻找右侧边界的二分搜索
int binarySearch(vector<int>& nums, int targer){
int left = 0, right = nums.size() - 1;
while(left <= right){
int mid = left + (right - left) / 2;
if(target >= nums[mid])
left = mid + 1;
else if(target < nums[mid])
right = mid - 1;
}
if(right < 0 || nums[right] != target)
return -1;
return right;
}