题目描述

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

假设你有 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 是第一个错误的版本。

示例 2:

输入:n = 1, bad = 1
输出:1

题目分析

题目指出,应尽可能减少程序对于API的调用,暗示了本题不应该用常规的暴力解法。所以在本题中我选择使用二分查找算法来解题。

第一步:确定左右区间

在二分查找算法中,首先应当确定好左右边界,考虑好边界情况。

在本题中,n从1开始,到n结束,在1到n之间必有目标答案

所以设定初始左区间left=0

初始右区间right=n

第二步:使用二分法查找答案

首先考虑特殊情况,排除特殊情况的干扰

即先判断一下第一个版本是不是错误的版本,如果是,则直接返回1。

然后循环判断中间版本与目标版本的关系

如果中间版本是错误版本但不是第一个错误版本,则说明第一个错误版本在该数组的左边,可以将右边区间舍去

如果中间版本是正确的版本,则说明目标版本在该数组的右边,可以将左边区间舍去

如果上述两种情况都不符合,则说明此时中间版本就是第一个错误版本,直接返回这个值即可。

题解代码

// The API isBadVersion is defined for you.
// bool isBadVersion(int version);

class Solution {
public:
    int firstBadVersion(int n) {//bool isBadVersion(int n)可用于判断是否为错误版本
        int left,right,middle;
        left=1;
        right=n;
        if(isBadVersion(1)){
            return 1;
        }
        while (left<=right){
            middle=left+((right-left)/2);
            if(isBadVersion(middle-1) && isBadVersion(middle)){//如果middle&middle-1都是错误的版本
                right=middle-1;//则表明出现错误的版本在左边区间,应将右边区间舍去
            } else if(!isBadVersion(middle-1) && !isBadVersion(middle)) {//如果middle&middle-1都不是错误的版本
                left=middle+1;//则表明出现错误的版本在右边区间,应将左边区间舍去
            } else{
                return middle;
            }
        }
        return 1;//这里是为了防止编译错误
    }
};

Q.E.D.