【力扣】第一个错误的版本:logn极速题解

题目描述

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

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

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

示例:

给定 n = 5,并且 version = 4 是第一个错误的版本。

调用 isBadVersion(3) -> false
调用 isBadVersion(5) -> true
调用 isBadVersion(4) -> true

所以,4 是第一个错误的版本。

题解

这是一道较为简单的题目,但是有一个小陷阱。除此之外,这道题的算法是比较显然的。

方法一:线性遍历 [超时]

最直接的方法是进行一次线性扫描,即对 [1…n]都调用一次isBadVersion

public int firstBadVersion(int n) {
    for (int i = 1; i < n; i++) {
        if (isBadVersion(i)) {
            return i;
        }
    }
    return n;
}

这样会超时
分析:时间复杂度O(n)O(n),空间复杂度O(1)O(1)

方法二:二分[通过]!

不难看出,这道题可以用经典的二分查找算法求解。我们通过一个例子,来说明二分查找如何在每次操作中减少一半的搜索空间,以此减少时间复杂度。

场景一:isBadVersion(mid) => false

 1 2 3 4 5 6 7 8 9
 G G G G G G B B B       G = 正确版本,B = 错误版本
 |       |       |
left    mid    right

场景一中,isBadVersion(mid) 返回 false,因此我们知道 mid 左侧(包括自身)的所有版本都是正确的。所以我们令 left=mid+1,把下一次的搜索空间变为 [mid + 1, right]。
不多说给代码:

public int firstBadVersion(int n) {
    int left = 1;
    int right = n;
    while (left < right) {
        int mid = left + (right - left) / 2;
        if (isBadVersion(mid)) {
            right = mid;
        } else {
            left = mid + 1;
        }
    }
    return left;
}

题目来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/first-bad-version
大家快去挑战吧?!😊

posted @ 2020-04-18 11:30  Aeterna_Gungnir  阅读(151)  评论(0编辑  收藏  举报