LeetCode278. 第一个错误的版本
在入手了《算法图解》之后,静下心来开始刷题。
第一道题目描述如下:
题目分析:
这道题目是要求从一个最小值为1,依次递增1的有序数组中找到一个badVersion,从描述中我们可以得知,如果x是badVersion,那么大于x的数都会是badVersion,我们的目的就是要找到这个数。
题解:
这道题最适合的就是二分法,我们知道,二分法的时间复杂度为O(log n)。接下来通过画图的方式来分析一下步骤。
元素中有6个元素,其中最小值low为1,最大值high为6。我们可以得到初始时中间数mid为(1+6)/2=3(向下取整)。我们定义第一个错误的版本为4
此时badVersion(3)为false,所以可以得出结论一:第一个错误的版本所在的范围比3大。
我们将范围缩小,这个时候low=mid+1
此时badVersion(4)为true,我们不能仅凭这一点就确定结果。因为描述说到“由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。”,所以我们还需要去获取badVersion(4-1)的结果,如果为true,说明4不是最终结果,如果结果是false,说明4是最终结果。
最后我的代码如下图:
在跑测试用例时出现了两个问题,第一个是对于n=1,badVersion=1(导致死循环)或n=2,badVersion=2(导致最终结果为-1)这样的情况,我没有考虑进去。
第二个问题是对于两个不超过int的值求mid,最终结果溢出得到了负数(也可以用这种方法去避免 int mid = low + (high - low) / 2),导致死循环,说明基础不牢固,还需要多花时间背诵。
最后虽然是通过了所有用例,但是性能方面还差得很多。我们来学习下更好的方法。
public class Solution extends VersionControl {
public int firstBadVersion(int n) {
int left = 1, right = n;
while (left < right) { // 循环直至区间左右端点相同
int mid = left + (right - left) / 2; // 防止计算时溢出
if (isBadVersion(mid)) {
right = mid; // 答案在区间 [left, mid] 中
} else {
left = mid + 1; // 答案在区间 [mid+1, right] 中
}
}
// 此时有 left == right,区间缩为一个点,即为答案
return left;
}
}