二分查找的模板与边界问题
二分查找有两套模板,模板A代码如下:
1 | int bsearch_1(int l, int r) |
模板B代码如下: 1
2
3
4
5
6
7
8
9
10int bsearch_2(int l, int r)
{
while (l < r)
{
int mid = (l + r + 1) /2;
if (check(mid)) l = mid;
else r = mid - 1;
}
return l;
}
两套代码有什么区别
- 模板A区间[l,r]划分成[l,mid]和[mid+1,r],更新操作是
r=mid
或者l=mid+1
,计算mid时不需要加1,即mid=(l+r)/2
。 - 模板B区间[l,r]划分成[l,mid-1]和[mid,r],更新操作是
r=mid-1
或者l=mid
,计算mid时不需要加1,即mid=(l+r+1)/2
。
为什么使用两套模板的mid计算方法不同?
当使用模板B时,会有以下这种特殊情况:r=l+1
。此时,如果使用mid=(l+r)/2
,向下取整,使得mid=l
,从而形成无限循环。
什么时候用模板A?什么时候用模板B?
左边界要更新为l=mid+1
,使用模板A。
左边界要更新为l=mid
,则使用模板B。
数据溢出怎么办?
把mid的计算方式更改为mid=l+((r-l)/2)
。
Example
你现在已经完全掌握二分查找了,快来试试看吧:leetcode-33.
搜索旋转排序数组 示例代码: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41class Solution {
public:
int search(vector<int>& nums, int target) {
//使用模板A,找到旋转点,用p储存之
int l = 0, r = nums.size() - 1;
while (l < r)
{
int mid = (l + r)/2;
if (nums[mid] < nums[r])
r = mid;
else l = mid + 1;
}
int p = l;
//[0,p]为有序数组,使用模板A二分查找
r = p - 1, l = 0;
while (l < r)
{
int mid = (l + r)/2;
if (nums[mid] >= target)
r = mid;
else l = mid + 1;
}
if(nums[l] == target)
return l;
//p之后为有序数组,使用模板A二分查找
l = p, r = nums.size() - 1;
while (l < r)
{
int mid = (l + r)/2;
if (nums[mid] >= target)
r = mid;
else l = mid + 1;
}
if(nums[l] == target)
return l;
else
return -1;
}
};