【LeetCode题解】#704 二分查找 & #278 第一个错误的版本

185 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第22天,点击查看活动详情

704 二分查找

直达:704 二分查找

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

快速解法

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var search = function(nums, target) {
    let left = 0;
    let right = nums.length - 1;

    while(left <= right) {
        const mid = Math.floor((right - left) / 2) + left;
        if (nums[mid] < target) {
            left = mid + 1;
        } else if (nums[mid] > target) {
            right = mid - 1;
        } else {
            return mid;
        }
    }

    return -1;
};

思路:

已知数组为有序数组,所以可以使用二分查找法来查找目标。

二分查找法是比较基础的算法,可以定义 leftright 来表示查找范围,在条件允许的情况下(left <= right),不断定义中点 mid,并通过中点的值和目标值进行比较不断确认查找范围,知道找到目标。

复杂度分析:

  • 时间复杂度:O(log n)n 是数组的长度,log n 是二分查找消耗的时间。
  • 空间复杂度:O(1)

278 第一个错误的版本

直达:278 第一个错误的版本

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

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

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

快速解法

/**
 * Definition for isBadVersion()
 * 
 * @param {integer} version number
 * @return {boolean} whether the version is bad
 * isBadVersion = function(version) {
 *     ...
 * };
 */

/**
 * @param {function} isBadVersion()
 * @return {function}
 */
var solution = function(isBadVersion) {
    /**
     * @param {integer} n Total versions
     * @return {integer} The first bad version
     */
    return function(n) {
        let left = 1;
        let right = n;
        
        while (left < right) {
            const mid = Math.floor((right - left) / 2) + left;
            if (isBadVersion(mid)) {
                right = mid;
            } else {
                left = mid + 1;
            }
        }

        return left;
    };
};

思路:

这道题主要在于一开始可能没法理解,其实就是通过调用参数传入的函数 isBadVersion 来判断是否是错误版本,isBadVersion(mid) = true 表示是错误版本。

然后和上一题一样,使用二分查找来解决,略有不同的是,查找条件是 left < right,是实操中:

  • 每次判断是错误版本,会设置 right = mid,保证 right 是错误版本
  • 每次判断是正确版本,会设置 left = mid + 1,而 mid 始终是正确版本,left 却有可能是错误版本
  • left 是错误版本时,要么进入新的循环,但是 mid 始终是错误版本,所以 right 的值会逐渐接近 left 的值,即 left === right,就是第一次错误版本
  • left 是错误版本时,要么不进入新的循环,即 left === right,就是第一次错误版本

复杂度分析:

  • 时间复杂度:O(log n)n 是数组的长度,log n 是二分查找消耗的时间。
  • 空间复杂度:O(1)