二分查找
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-search
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解析:最经典的二分查找例子,用二分查找寻找一个精确的数字。
条件:left <= right
区间更改:当所找的数在目标数的左边 left = mi - 1
当所找的数在目标数的右边 right = mi + 1
int search(int* nums, int numsSize, int target){
int lo = 0,hi = numsSize-1;
while(lo<=hi){
int mi = lo+(hi-lo)/2; //防止计算溢出
if(nums[mi]==target){
return mi;
}else if(nums[mi]<target){
lo = mi + 1;
}else if(nums[mi]>target){
hi = mi - 1;
}
}
return -1;
}
第一个错误版本
你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。
假设你有 n 个版本 [1, 2, ..., n],你想找出导致之后所有版本出错的第一个错误的版本。
你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/first-bad-version
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解析:二分查找的变种,寻找FIRST OCCURENCE OF A NUMBER or LAST OCCURENCE OF A NUMBER,力扣的题目给的是找出第一个出错的产品也就是找出第一个数字。
原版题目:search first occurence of a number
int binary search(int *num,int numsSize,target){
int left = 0,right = numsSize - 1;
while(left<high){
int mi = left + (right - left) / 2;
if(num[mi]<target){
left = mi + 1;
}else{
right = mi;
}
}
}
条件:left < right
区间更改:(first)当目标数大于所找到的数时 left = middle + 1
其他 right = middle
(last)当目标数小于所找到的数时 right = middle - 1
其他 left = middle
// The API isBadVersion is defined for you.
// bool isBadVersion(int version);
int firstBadVersion(int n) {
int lo = 1,hi = n;
while(lo<hi){
int mi = lo + (hi-lo) / 2;
if(isBadVersion(mi)){
hi=mi;
}else{
lo=mi+1;
}
}
return lo;
}
搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/search-insert-position
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解析:寻找一个最接近target的数字。该题产生了一些变式,就是当target是区间中的一个数字时,要返回它本身的下标。
原版题目:find a closest number of target
int binary search(int *num,int numSize,int target){
int left = 0,right = numSize - 1;
while(left<right-1){
int mi = left = (high-left) / 2;
if(nums[mi]<target)left = mi;
else right = mi;
}
//循环最终会出现两个数
if(target<num[mi]) return left;//目标在左边
if(target>num[mi]) return right;//目标在右边
else k-left>right-k?right:left;//在中间
}
条件:left < high - 1
区间改变:如果target在左边 right = middle
其他 left = middle
出口:根据target所处位置进行return
int searchInsert(int* nums, int numsSize, int target){
int lo = 0,hi = numsSize-1;
while(lo<hi-1){
int mi = lo+(hi-lo)/2;
if(nums[mi]>target)hi = mi;
else lo = mi;
}
if(nums[hi]<target)return hi+1;//值坐落在hi右边
else if(nums[lo]>target)return lo;//值坐落在lo左边
else if(nums[lo]==target)return lo;
return lo+1;
}