文章目录
一、二分查找-basic
时间复杂度 :O(logn);
要求:排序数组。
1. caution:
循环不变量的定义 :// 在arr[l…r]之中查找target
循环继续条件: l <= r ,因为循环不变量定义了是闭区间,所以要加上等号,使得相等的时候还继续循环。
// 二分查找法,在有序数组arr中,查找target
// 如果找到target,返回相应的索引index
// 如果没有找到target,返回-1
template<typename T>
int binarySearch(T arr[], int n, T target){
// 在arr[l...r]之中查找target
int l = 0, r = n-1;
while( l <= r ){
//int mid = (l + r)/2;
// 防止极端情况下的整形溢出,使用下面的逻辑求出mid
int mid = l + (r-l)/2;
if( arr[mid] == target )
return mid;
if( arr[mid] > target )
r = mid - 1;
else
l = mid + 1;
}
return -1;
}
二、upper、lower bound
upper(找上界):找到大于target 的最小值。
lower (找下界):找到大于等于target 的最小值。
如果数组中没有target,那么upper和lower 返回相同索引。
有的地方定义不同,反正代码跟着定义走就行,学会了的话,怎样变种都能做。
1. caution:
循环不变量的定义 :// 在arr[l…r]之中寻找解
循环继续条件: l < r //结束时,l==r ,随便返回一个
上边界初始化: r = length; //上边界也有可能是解(target大于所有值,返回溢出的位置)
右边界更新 : r = mid; //因为解有可能是mid。
2.upper bound
template<typename T>
int upper_bound(T arr[], int n, T target){
int l = 0, r = n;
while(l < r){
int mid = l + (r - l) / 2;
if(arr[mid] <= target)
l = mid + 1;
else // nums[mid] > target
r = mid;
}
return l;
}
3.lower bound
template<typename T>
int lower_bound(T arr[], int n, T target){
int l = 0, r = n;
while(l < r){
int mid = l + (r - l) / 2;
if(arr[mid] < target)
l = mid + 1;
else // nums[mid] >= target
r = mid;
}
return l;
}
二、ceil、floor
ceil:
- 如果数组中存在target,返回target中的最大索引;
- 如果不存在target,返回upper(大于这个值的最小元素索引);
- 如果target大于所有的值,返回数组个数n(即数组上溢出的索引)
floor:
- 如果找到target,返回第一个target 的索引;
- 如果没有找到target,返回比target小的最大值的索引;
- 如果target小于所有的值,返回-1(即数组下溢出的索引);
1. caution:
-
上下边界的选择:floor:-1 ~ n-1;ceil:0 ~ n;
-
mid 的上下取整:floor :mid = l + (r-l+1)/2; //向上取整避免死循环
(因为有边界每次更新都是小于mid 的,所以让mid向上取整,并不会进入死循环;而其他的都是下边界更新时候是 l = mid+1,所以让mid向下取整没有问题)
- 找到与没找到之间的判断和返回值。
2.ceil
template<typename T>
int ceil(T arr[], int n, T target){
// 寻找比target大的最小索引值
int l = 0, r = n;
while( l < r ){
// 使用普通的向下取整即可避免死循环
int mid = l + (r-l)/2;
if( arr[mid] <= target )
l = mid + 1;
else // arr[mid] > target
r = mid;
}
assert( l == r );
// 如果该索引-1就是target本身, 该索引+1即为返回值
if( r - 1 >= 0 && arr[r-1] == target )
return r-1;
// 否则, 该索引即为返回值
return r;
}
2.floor
template<typename T>
int floor(T arr[], int n, T target){
// 寻找比target小的最大索引
int l = -1, r = n-1;
while( l < r ){
// 使用向上取整避免死循环
int mid = l + (r-l+1)/2;
if( arr[mid] >= target )
r = mid - 1;
else
l = mid;
}
assert( l == r );
// 如果该索引+1就是target本身, 该索引+1即为返回值
if( l + 1 < n && arr[l+1] == target )
return l + 1;
// 否则, 该索引即为返回值
return l;
}
三、相关问题
875.爱吃香蕉的珂珂
1011 .在 D 天内送达包裹的能力