【力扣】第一个错误的版本: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;
}
这样会超时
分析:时间复杂度,空间复杂度
方法二:二分[通过]!
不难看出,这道题可以用经典的二分查找算法求解。我们通过一个例子,来说明二分查找如何在每次操作中减少一半的搜索空间,以此减少时间复杂度。
场景一: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
大家快去挑战吧?!😊