二分查找模板
1.base版本(l=mid+1,r=mid-1)
void bin_search(vector<int>& arr,int target){
int ans=-1;
int l=0,r=arr.size()-1;
int mid=l+(r-l)/2;
while(l<=r){
mid=l+(r-l)/2;
if(arr[mid]==target){
ans=mid;break;
}else if(arr[mid]>target){
r=mid-1;
}else{
l=mid+1;
}
}
return ans;
}
2.template 1 (left=mid+1;right=mid,mid不加1)
int bin_search(int left, int right) {
while (left < right) {
int mid = (left + right) / 2; // 注意防止溢出
if (check(mid)) // 判断 mid 是否满足查找条件
left = mid + 1; // 结果落在 [mid+1, right] 区间
else
right = mid; // 结果落在 [left, mid] 区间
}
return left;
}
3.template 2(left=mid;right=mid-1,mid加1)
int bin_search(int left, int right) {
while (left < right) {
// 注意防止溢出
int mid = (left + right + 1) / 2;
if (check(mid))
// 结果落在 [left, mid-1]
right = mid - 1;
else
// 结果落在 [mid, right]
left = mid;
}
return left;
}
两个模板最后都是要收缩到区间
[
l
e
f
t
,
l
e
f
t
+
1
]
\ [left, left+1]
[left,left+1] 里进行最后一次
c
h
e
c
k
check
check:
对于模板一,计算得到
m
i
d
=
l
e
f
t
mid= left
mid=left,区间往左收缩是进入
r
i
g
h
t
=
m
i
d
right = mid
right=mid ,区间往右收缩是进入
l
e
f
t
=
m
i
d
+
1
left = mid + 1
left=mid+1,结束循环,所以更新
m
i
d
mid
mid 要用
m
i
d
=
(
l
e
f
t
+
r
i
g
h
t
)
/
2
mid = (left + right)/2
mid=(left+right)/2
对于模板二,计算得到
m
i
d
=
r
i
g
h
t
mid = right
mid=right,区间往左收缩是进入
r
i
g
h
t
=
m
i
d
−
1
right = mid - 1
right=mid−1 ,区间往右收缩是进入
l
e
f
t
=
m
i
d
left = mid
left=mid,结束循环,所以更新
m
i
d
mid
mid要用
m
i
d
=
(
l
e
f
t
+
r
i
g
h
t
+
1
)
/
2
mid = (left + right + 1)/2
mid=(left+right+1)/2
例1:左边界问题
查找元素
t
a
r
g
e
t
target
target的第一个位置,相当于查找 大于等于
t
a
r
g
e
t
target
target 的第一个元素位置:
如果
n
u
m
s
[
m
i
d
]
<
t
a
r
g
e
t
nums[mid] < target
nums[mid]<target,此时
t
a
r
g
e
t
target
target 应该落在 右半区间
[
m
i
d
+
1
,
r
i
g
h
t
]
[mid+1, right]
[mid+1,right];
如果
n
u
m
s
[
m
i
d
]
>
=
t
a
r
g
e
t
nums[mid] >= target
nums[mid]>=target,此时
t
a
r
g
e
t
target
target应该落在 左半区间
[
l
e
f
t
,
m
i
d
]
[left, mid]
[left,mid],因为
m
i
d
mid
mid可能就是
t
a
r
g
e
t
target
target,所以还需要进一步比较;
因而选择
c
h
e
c
k
(
m
i
d
)
check(mid)
check(mid)为
n
u
m
s
[
m
i
d
]
<
t
a
r
g
e
t
nums[mid] < target
nums[mid]<target,区间更新条件分别是
l
e
f
t
=
m
i
d
+
1
left = mid + 1
left=mid+1;
r
i
g
h
t
=
m
i
d
right = mid
right=mid;
int searchFirst(vector<int> &nums, int target) {
int left = 0, right = nums.size() - 1;
while (left < right) {
int mid = (left + right) >> 1;
if (nums[mid] < target)
left = mid + 1;
else
right = mid;
}
return nums[left] == target ? left : -1;
}
例2:右边界问题
查找元素
t
a
r
g
e
t
target
target 的最后一个位置,相当于查找 小于等于
t
a
r
g
e
t
target
target 的最后一个元素位置:
如果
n
u
m
s
[
m
i
d
]
>
t
a
r
g
e
t
nums[mid] > target
nums[mid]>target,此时
t
a
r
g
e
t
target
target 应该落在 左半区间
[
l
e
f
t
,
m
i
d
−
1
]
[left, mid-1]
[left,mid−1];
如果
n
u
m
s
[
m
i
d
]
<
=
t
a
r
g
e
t
nums[mid] <= target
nums[mid]<=target,此时
t
a
r
g
e
t
target
target 应该落在 右半区间
[
m
i
d
,
r
i
g
h
t
]
[mid, right]
[mid,right],因为
m
i
d
mid
mid可能就是
t
a
r
g
e
t
target
target,所以还需要进一步比较
因而选择
c
h
e
c
k
(
m
i
d
)
check(mid)
check(mid) 为
n
u
m
s
[
m
i
d
]
>
t
a
r
g
e
t
nums[mid] > target
nums[mid]>target,区间更新条件分别是
r
i
g
h
t
=
m
i
d
−
1
right = mid-1
right=mid−1;
l
e
f
t
=
m
i
d
left = mid
left=mid;
int searchLast(vector<int> &nums, int target) {
int left = 0, right = nums.size() - 1;
while (left < right) {
int mid = (left + right + 1) / 2;
if (nums[mid] <= target)
left = mid;
else
right = mid - 1;
}
return nums[left] == target ? left : -1;
}
参考文章:
https://blog.csdn.net/charlsonzhao/article/details/124063879