LeetCode破解之错误版本

846 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情

题目说明

你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。

假设你有 n 个版本 [1, 2, ..., n],你想找出导致之后所有版本出错的第一个错误的版本。

你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。

示例 1:

输入:n = 5, bad = 4 输出:4 解释: 调用 isBadVersion(3) -> false 调用 isBadVersion(5) -> true 调用 isBadVersion(4) -> true 所以,4 是第一个错误的版本。

思路分析

这个题目。。刚开始看的我迷迷糊糊,发现其他兄弟们也迷迷糊糊,后来才发现其实这题的目的就是让你在 firstBadVersion(n)里面传递一个有多少个版本的数值,然后再用isBadVersion(版本号)判断从1~n之间最开始错误的版本号,要求就是怎么调用最少的isBadVersion实现这个要求。

二分查找算法

思路:利用二分查找常规模板,当lo==hi时while循环结束,此时返回lo或者hi都是对的,我一般用此方法做二分查找的模板,出错较少。左边都是false,右边都是true,题目要求返回第一个true版本,所以当false时lo =mid+1;

因为要一直调用函数的原因,所以left和right比引索来讲都增加了1. 一般来讲right都是取size+1的,但是这题发现即便到最后了left也会加1,刚好能到达size+1,所以一开始取size=n也行
public class Solution extends VersionControl {
    public int firstBadVersion(int n) {
        int lo = 0,hi = n;
        while(lo<hi){
            int mid = (lo+hi)>>>1;
            if(isBadVersion(mid)){
                hi=mid;
            }else{
                lo=mid+1;
            }
        }
        return lo;
    }
}

注意

今天刚刚学到的,不能用(left+right)/2形式,当left和right都是int,两个值的初始值都超过int限定大小的一半,那么left+right就会发生溢出,所以应该用left+(right-left)/2来防止求中值时候的溢出。返回 lo 或者 hi 都行,因为终止条件是 lo == hi.

一定要防止int溢出,这种溢出错误的是最常见的也是最难排查的,明明只是一个小问题,却能卡着你一直过不去。刚开始我int溢出真是麻了,真没想到。一开始我还去纠结于二分都会超时,哪还有什么方法可以用。除此之外还有一个点。

[1.n)范围是左闭右开区间 所以high =mid 而不是high= mid-1;如果闭区间[0,n-1] while(low <= high) 则需要high=mid-1