2022.2.7 二分

二分查找:如果一个问题,待查找的是整数,且知道范围,大概可以使用二分查找算法

278. 第一个错误的版本

你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。

假设你有 n 个版本 [1, 2, ..., n],你想找出导致之后所有版本出错的第一个错误的版本。

你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。

示例 1:

输入:n = 5, bad = 4
输出:4
解释:
调用 isBadVersion(3) -> false 
调用 isBadVersion(5) -> true 
调用 isBadVersion(4) -> true
所以,4 是第一个错误的版本。

示例 2:

输入:n = 1, bad = 1
输出:1
// The API isBadVersion is defined for you.
// bool isBadVersion(int version);

int firstBadVersion(int n) 
{
    if(n==1) return 1;
    long low=1,high=n,mid;//注意long
    while(low<high)
    {
        mid=(low+high)/2;
        if(isBadVersion(mid))//如果mid是错误版本,为了找到第一个错误版本且减少对调用 API 的次数,因此使用二分的方法到左区间去查找
            high=mid;
        else//未找到,到右区间继续找错误版本    
            low=mid+1;
    }
    return low;//理解:区间内未找到错误版本,那么最开始的版本就是错误的
}

官方题解:

思路及算法

因为题目要求尽量减少调用检查接口的次数,所以不能对每个版本都调用检查接口,而是应该将调用检查接口的次数降到最低。

注意到一个性质:当一个版本为正确版本,则该版本之前的所有版本均为正确版本;当一个版本为错误版本,则该版本之后的所有版本均为错误版本。我们可以利用这个性质进行二分查找

具体地,将左右边界分别初始化为 111 和 nnn,其中 nnn 是给定的版本数量。设定左右边界之后,每次我们都依据左右边界找到其中间的版本,检查其是否为正确版本。如果该版本为正确版本,那么第一个错误的版本必然位于该版本的右侧,我们缩紧左边界;否则第一个错误的版本必然位于该版本及该版本的左侧,我们缩紧右边界。

这样我们每判断一次都可以缩紧一次边界,而每次缩紧时两边界距离将变为原来的一半,因此我们至多只需要缩紧 O(log⁡n)O(\log n)O(logn) 次。

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

提示:

  • 1 <= nums.length <= 104
  • -104 <= nums[i] <= 104
  • nums无重复元素升序排列数组
  • -104 <= target <= 104
int searchInsert(int* nums, int numsSize, int target)
{
    int left=0;
    int right=numsSize-1;
    int middle=0;

    while(left<=right)
    {
        middle=(left+right)/2;
        if(nums[middle]>target)
            right=middle-1;
        if(nums[middle]<target)
            left=middle+1;
        if(nums[middle]==target)
            return middle;
    }

    return left;//
}

复杂度分析:

  •     时间复杂度:O(log⁡n)O(\log n)O(logn),其中 nnn 为数组的长度。二分查找所需的时间复杂度为 O(log⁡n)O(\log n)O(logn)。
  •     空间复杂度:O(1)O(1)O(1)。我们只需要常数空间存放若干变量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值