解决情况:当数组有序,要求寻找某个目标值(或者第一个出现该目标值的位置,最后一个出现目标值的位置),且时间复杂度要求O(logn).
1.704. 二分查找
题目描述:
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
示例:
输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4
输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1
代码:
int search(int* nums, int numsSize, int target){
int l=0;
int r=numsSize-1;
int mid=0;
while(l<=r)
{
mid=(l+r)/2;
if(nums[mid]<target)
{
l=mid+1;
}
else if(nums[mid]>target)
{
r=mid-1;
}
else
{
return mid;
}
}
mid=-1;
return mid;
}
2.278. 第一个错误的版本
题目描述:
你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。
假设你有 n 个版本 [1, 2, ..., n],你想找出导致之后所有版本出错的第一个错误的版本。
你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。
示例:
输入:n = 5, bad = 4
输出:4
解释:
调用 isBadVersion(3) -> false
调用 isBadVersion(5) -> true
调用 isBadVersion(4) -> true
所以,4 是第一个错误的版本。
输入:n = 1, bad = 1
输出:1
解答描述:
典型的二分法查找的变形,要找到第一个isBadVersion为true的位置。
某个错误版本之后的版本都是错误的,此时搜索前半段;某个正确版本之前的版本都是正确的,搜索后半段。
在这里要注意n的范围为1~2^31-1,直接mid=(l+r)/2,可能会超出int 的表示范围,而改用double又会使得mid=(l+r)/2的结果不精确,不会默认保留整数部分,所以换成等价式mid=l+(r-l)/2!!
代码:
// The API isBadVersion is defined for you.
// bool isBadVersion(int version);
int firstBadVersion(int n) {
int l=1;
int r=n;
int mid=0;
while(l<=r)
{
mid=l+(r-l)/2;//*****直接令mid=(l+r)/2;可能会导致int溢出
if(isBadVersion(mid)==true)
{
r=mid-1;
}
else
{
l=mid+1;
}
}
return l;
}
3.35. 搜索插入位置
题目描述:
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。
示例:
示例 1:
输入: nums = [1,3,5,6], target = 5
输出: 2
示例 2:
输入: nums = [1,3,5,6], target = 2
输出: 1
示例 3:
输入: nums = [1,3,5,6], target = 7
输出: 4
示例 4:
输入: nums = [1,3,5,6], target = 0
输出: 0
示例 5:
输入: nums = [1], target = 0
输出: 0
代码:
int searchInsert(int* nums, int numsSize, int target){
int l=0;
int r=numsSize-1;
int mid=0;
bool flag=false;
while(l<=r)//二分查找
{
mid=(l+r)/2;
if(nums[mid]<target)
{
l=mid+1;
}
else if(nums[mid]>target)
{
r=mid-1;
}
else
{
flag=true;
return mid;
}
}
if(!flag)//找不到target
{
mid=l;
}
return mid;
}