问题描述:
你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。
假设你有 n
个版本 [1, 2, ..., n]
,你想找出导致之后所有版本出错的第一个错误的版本。
你可以通过调用 bool isBadVersion(version)
接口来判断版本号 version
是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。
示例:
给定 n = 5,并且 version = 4 是第一个错误的版本。
调用 isBadVersion(3) -> false
调用 isBadVersion(5) -> true
调用 isBadVersion(4) -> true
所以,4 是第一个错误的版本。
解法一:
逐个扫描,直到出现第一个true。
代码如下:
// Forward declaration of isBadVersion API.
bool isBadVersion(int version);
class Solution {
public:
int firstBadVersion(int n) {
int i = 1;
for(i ;i <= n;i++){
if(isBadVersion(i)) return i;
}
return i;
}
};
这个方法会超时。
复杂度分析
时间复杂度:O(n)。在最坏的情况下,最多可能会调用 isBadVersion
n−1 次,因此总的时间复杂度为 O(n)。
空间复杂度:O(1)。
解法二:
二分法
借用一下力扣官方的图解:
代码如下:
// Forward declaration of isBadVersion API.
bool isBadVersion(int version);
class Solution {
public:
int firstBadVersion(int n) {
if(isBadVersion(1)) return 1;
return scan(1,n,n);
}
int scan(long left, long right, int n){
long mid = (left + right)/2;//因为此处mid使用int会溢出,虽以声明为long,也可以使用int mid = left + (right - left) / 2;避免溢出
if(mid==n) return mid;
if(isBadVersion(mid)==false){
if(isBadVersion(mid+1)==true){
return mid+1;
}
else{//(isBadVersion(mid+1)==false)
return scan(mid,right,n);
}
}
else{
return scan(left,mid,n);
}
}
};
复杂度分析
- 时间复杂度:O*(logn)。搜索空间每次减少一半,因此时间复杂度为 O(log*n)。
- 空间复杂度:O(1)。