1 题目
第一个坏版本(First Bad Version)
lintcode:题号——74,难度——medium
2 描述
代码库的版本号是从 1 到 n 的整数。某一天,有人提交了错误版本的代码,因此造成自身及之后版本的代码在单元测试中均出错。请找出第一个错误的版本号。
你可以通过 isBadVersion 的接口来判断版本号 version 是否在单元测试中出错。(调用 isBadVersion 的次数越少越好)
/**
* class SVNRepo {
* public:
* static bool isBadVersion(int k);
* }
* you can use SVNRepo::isBadVersion(k) to judge whether
* the kth code version is bad or not.
*/
样例:
输入:n = 5,first bad version is 4
输出:4
解释:isBadVersion(3) -> false
isBadVersion(5) -> true
isBadVersion(4) -> true
因此可以确定第四个版本是第一个错误版本。
3 思路
问题可以转化为在类似“OOOOXXXX”的序列中寻找分割点的问题,如果不考虑时间复杂度的话,可以从头遍历,耗时O(n),但是要求调用isBadVersion()接口的次数越少越好,在有序序列中的查找,考虑使用二分法将耗时降为O(log n)。
- 找到中间位置的元素;
- 与目标元素比较,确定目标元素所在的区间,缩小目标区间;
- 重复以上操作,直到找到或者结束。
套用之前的经典二分搜索1的模版,注意事项如下:
- 循环中与目标元素的比较变成了对isBadVersion()接口的调用;
- 跳出循环之后,对剩下的两个元素先检查头,再检查尾。
3.2 图解
3.2 时间复杂度
算法的时间复杂度为O(log n)
3.3 空间复杂度
算法的空间复杂度为O(1)
4 源码
注意事项:
- C++调用静态方法使用“类名::函数名”的方式;
- 注意接口isBadVersion()的返回值,false表示好版本,true表示坏版本,不要搞反了。
C++版本:
/**
* @param n: 版本号数
* @return: 第一个坏的版本号(序号从1开始)
*/
int findFirstBadVersion(int n) {
// write your code here
int start = 1;
int end = n;
int mid = 0;
while (start + 1 < end)
{
mid = start + (end - start) / 2;
if (SVNRepo::isBadVersion(mid) == true)
{
end = mid;
}
else
{
start = mid;
}
}
if (SVNRepo::isBadVersion(start) == true)
{
return start;
}
return end;
}
经典二分搜索:https://blog.csdn.net/SeeDoubleU/article/details/118271548 ↩︎