Nico的刷题日记(一)

LeetCode278. 第一个错误的版本


在入手了《算法图解》之后,静下心来开始刷题。
第一道题目描述如下:
截图来自LeetCode

题目分析:
这道题目是要求从一个最小值为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;
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值