目录
问题
思路:
因为是排好序的数组,所以第一反应就是运用二分查找
仍画一个表格进行分析,其中last 表示的是 最后一次看到的好版本
例子1: n = 7, bad = 3
因为在发现mid是坏的,跟last还差的很远的时候,我加入了一段代码,让last向后看,看看接着的一个是不是还是对的,如果是,那last进1,min进2进行判断,如下表:
如果我的思路比较跳脱的话,没关系,建议先看我上一边关于二分法的笔记,然后再结合本题的代码实现,来进行理解,相信掌握了这个分析方法之后,所有的二分问题都会迎刃而解~
1 | 2 | 3 | 4 | 5 | 6 | 7 | |
step1 | min,last | mid | max | ||||
step2 | last | min,mid,max |
再举个栗子2: n = 5, bad = 3
这种情况下,step1在找到mid是坏的,但是与last有距离
同样道理,max—>mid-1=2; 检查last+1,发现还是好的,那last—>2,min—>3,这个时候进入下一轮循环是,max<min,跳出循环,return last+1 也就是3 就是正确答案
为什么跳出循环的时候,输出last+1呢,因为在发现本身是正确的mid的时候没有范围,而是让其往前继续找,导致错过了正解,而同时,last也在积极向后看,征求与mid前边的数字回合,所以当跳出循环的时候,也就是last其实记录的是最后一个对的,,那再加一,就是第一个错的。
1 | 2 | 3 | 4 | 5 | |
step1 | min,last | mid | max | ||
step2 | last,max | min | |||
代码实现:
/* The isBadVersion API is defined in the parent class VersionControl.
boolean isBadVersion(int version); */
public class Solution extends VersionControl {
public int firstBadVersion(int n) {
int min = 1;
int max = n;
if(isBadVersion(min)){
return min;
}
int last = 1;//用last表示上一个查找的错误的版本号
while(min<=max){
int mid = min + (max-min)/2;
//判断mid版本是否是错误的
if(isBadVersion(mid)){
//如果是错误的,那看一下是不是第一个错误的版本,也就是判断是否与last挨着
if(mid == last+1){
return mid;//如果挨着那就返回mid
}else{
//如果 不紧挨着,那last和 mid之间,可能存在更早的错误版本;
//先判断last的下一个是不是错的,如果是,直接返回
if(isBadVersion(last+1)) {
return last+1;
}
//如果下一个还不是错的,那更新last和min;
last = last+1;
min =last+1;
max = mid - 1;
}
}else{
last = mid;
min = mid + 1;
}
}
return last + 1;//如果找不到,说明last前的某一个值就是最后一个错的
}
}
效果:
emmm,速度还可以,但是内存消耗较大,还有待改进~