基本模板
int binSearch(vector<int>& nums, int target) {
int lo=0;
int hi=(...)//key 1
while(...){ //key 2
int mi=lo+((hi-lo)>>1);
if(nums[mi]<target){
(...)//key3
}else if(nums[mi]==target){
(...)//key3
}else if(nums[mi]>target){
(...)//key3
}
}
return (...);
}
version 1
int binSearch(vector<int>& nums, int target) {
int lo=0;
int hi=nums.size()-1;//key 1: 因为是左闭右闭区间
while(lo<=hi){ //key 2 :左闭右闭区间 [lo, hi],判断结束的条件!
int mi=lo+((hi-lo)>>1);
if(nums[mi]<target){
lo=mi+1;
//[mi+1,hi]
}else if(nums[mi]==target){
return mi;
//命中返回
}else if(nums[mi]>target){
hi=mi-1;
//[lo,mi-1]
}
}
return -1;
}
:::tips
- 左闭右闭区间
- 右边界可以取到,所以一开始是
nums.size()-1
- 判断命中即返回,有缺陷,找到的并不是右边第一个数或是左边第一个数
- 更新时的区间需要排除mid
:::
左闭右开区间版本
```cpp
int binSearch(vector
& nums, int target) { int lo=0; int hi=nums.size();//key 1: 因为是左闭右开
- 右边界可以取到,所以一开始是
while(lo<hi){ //key 2 :左闭右闭区间 [lo, hi],判断结束的条件!
int mi=lo+((hi-lo)>>1);
if(nums[mi]<target){
lo=mi+1;
//[mi+1,hi)
}else if(nums[mi]>=target){
hi=mi;
//[lo,mi)
}
}
return nums[lo]==target?lo:-1;
}
<a name="zWo2X"></a>
# 寻找左侧边界的二分搜索
```cpp
int binSearch(vector<int>& nums, int target) {
int lo=0;
int hi=nums.size();//key 1: 因为是左闭右开
while(lo<hi){ //key 2 :左闭右闭区间 [lo, hi),判断结束的条件!
int mi=lo+((hi-lo)>>1);
if(nums[mi]==target){
hi=mi;//key!
}else if(nums[mi]<target){
lo=mi+1;
//[mi+1,hi)
}else if(nums[mi]>target){
hi=mi;
//[lo,mi)
}
}
if(lo>nums.size()) return -1;
return nums[lo]==target?lo:-1;
}
找到 target 时不要立即返回,而是缩小「搜索区间」的上界 right
,在区间[left, mid)
中继续搜索,即不断向左收缩,达到锁定左侧边界的目的。
寻找右边界
int binSearch(vector<int>& nums, int target) {
int lo=0;
int hi=nums.size();//key 1: 因为是左闭右开
while(lo<hi){ //key 2 :左闭右闭区间 [lo, hi),判断结束的条件!
int mi=lo+((hi-lo)>>1);
if(nums[mi]==target){
lo=mi+1;//key!
}else if(nums[mi]<target){
lo=mi+1;
//[mi+1,hi)
}else if(nums[mi]>target){
hi=mi;
//[lo,mi)
}
}
if(lo==0) return -1;
return nums[lo-1]==target?lo-1:-1;
}
左闭右闭区间
int findLe(vector<int>& nums, int target){
int lo=0;
int hi=nums.size()-1;
while(lo<=hi){
int mi=lo+((hi-lo)>>1);
if(nums[mi]==target){
hi=mi-1;
}else if(nums[mi]<target){
lo=mi+1;
}else if(nums[mi]>target){
hi=mi-1;
}
}
if(lo>=nums.size()||nums[lo]!=target) return -1;
return lo;
}
int findRi(vector<int>& nums, int target){
int lo=0;
int hi=nums.size()-1;
while(lo<=hi){
int mi=lo+((hi-lo)>>1);
if(nums[mi]==target){
lo=mi+1;
}else if(nums[mi]>target){
hi=mi-1;
}else if(nums[mi]<target){
lo=mi+1;
}
}
if(hi<0||nums[hi]!=target) return -1;
return hi;//lo-1;
}
左闭右开区间
int findRi(vector<int>& nums, int target) {
int lo=0;
int hi=nums.size();
while(lo<hi){
int mi=lo+((hi-lo)>>1);
if(nums[mi]==target){
lo=mi+1;
}else if(nums[mi]<target){
lo=mi+1;
}else if(nums[mi]>target){
hi=mi;
}
}
if(hi==0) return -1;
return nums[lo-1]==target?lo-1:-1;
}
int findLe(vector<int>& nums, int target) {
int lo=0;
int hi=nums.size();
while(lo<hi){
int mi=lo+((hi-lo)>>1);
if(nums[mi]==target){
hi=mi;
}else if(nums[mi]>target){
hi=mi;
}else if(nums[mi]<target){
lo=mi+1;
}
}
if(lo==nums.size()) return -1;
return nums[lo]==target?lo:-1;
}