leetcode笔记 | 704二分查找 278第一个错误的版本 35搜索插入位置(JavaScript)

524 阅读2分钟

【704】二分查找

CategoryDifficultyLikesDislikes
algorithmsEasy (56.01%)280-

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

个人解法

var search = function (nums, target) {
    if (!nums.includes(target)) {
        return -1;
    }
    if (nums[0] === target) {
        return 0;
    }
    if (nums[1] === target) {
        return 1;
    }
    let mid = parseInt(nums.length / 2)
    if (nums[mid] < target) {
        for (let i = mid + 1; i < nums.length; i++) {
            if (target === nums[i]) return i;
        }
    } else {
        for (let j = 0; j < mid; j++) {
            if (target === nums[j]) return j;
        }
    }
}

Accepted

  • 46/46 cases passed (84 ms)
  • Your runtime beats 58.95 % of javascript submissions
  • Your memory usage beats 39.58 % of javascript submissions (41.3 MB)

分析

之前的思路中,mid固定不变,没有参与循环,实际上只实现了一次二分。于是定义数组下标左右端点l、r,采用求l、r平均值的方式确定mid,mid可以随l、r的变化而改变。

优化

    let l = 0, r = nums.length;
    while (l <= r) {
        let mid = parseInt((l + r) / 2);
        if (nums[mid] === target) {
            return mid;
        } else {
            if (r - l === 1) {
                return -1;       // 只剩下一个数但仍不等于target的情况
            }
            else if (nums[mid] < target) {
                l = mid + 1;     // 新的循环范围舍弃mid,因为nums[mid]已经确定不等于target(否则就 return mid了)
            }
            else if (nums[mid] > target) {
                r = mid;
            }
        }
    }
}

Accepted

  • 46/46 cases passed (76 ms)
  • Your runtime beats 79.62 % of javascript submissions
  • Your memory usage beats 5.65 % of javascript submissions (41.6 MB)

【278】第一个错误的版本

CategoryDifficultyLikesDislikes
algorithmsEasy (45.31%)362-

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

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

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

个人解法(订误)

var solution = function (isBadVersion) {
    /**
     * @param {integer} n Total versions
     * @return {integer} The first bad version
     */
    return function (n) {
        // let arr = [];
        // for (let i = 0; i <= n; i++) {
        //     arr.push(i);
        // }
        // let l = 0, r = arr.length;  删去,不需要构建数组也可以使用二分法。
        let l = 1, r = n;
        while (l < r) {
            let mid = parseInt((l + r) / 2);
            //删去。通过将答案区间逼近为1的方法找到目标值。
            // if (isBadVersion(arr[mid]) === false && isBadVersion(arr[mid + 1]) === true) return mid + 1;
            if (isBadVersion(mid)) {    //if条件句本身就是布尔值,唉!
                r = mid;
            } else
                // else if (isBadVersion(arr[mid]) === false) {
                l = mid + 1;
            // } else {
            //     r = mid;
            // }
        }
        return l;
    };
};

Accepted

  • 22/22 cases passed (56 ms)
  • Your runtime beats 99.43 % of javascript submissions
  • Your memory usage beats 18.61 % of javascript submissions (37.8 MB)

分析

关键点在于,当l=r时,存在目标值的区间长度为1,即找到目标值。并且while循环条件设为l<r,l=r时可以跳出循环,返回结果。

如果将题【704】二分查找 换成同样的写法:

【704】优化

var search = function (nums, target) {
let l = 0, r = nums.length;
    while (l < r) {
        let mid = parseInt((l + r) / 2);
        if (nums[mid] < target) {
            l = mid + 1;
        }
        else {
            r = mid;
        }
    }
    if (nums[l] !== target) return -1;
    else return l;
}

Accepted

  • 46/46 cases passed (72 ms)
  • Your runtime beats 88.84 % of javascript submissions
  • Your memory usage beats 11 % of javascript submissions (41.5 MB)

同理可优化题【35】:

【35】搜索插入位置

CategoryDifficultyLikesDislikes
algorithmsEasy (46.96%)977-

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

个人解法

var searchInsert = function(nums, target) {
    const n = nums.length;
    let left = 0, right = n - 1, ans = n;
    while (left <= right) {
        let mid = Math.floor((left + right) / 2);
        if (target <= nums[mid]) {
            ans = mid;
            right = mid;
        } else {
            left = mid + 1;
        }
    }
    return ans;
}; 

Accepted

  • 62/62 cases passed (96 ms)
  • Your runtime beats 14.67% of javascript submissions
  • Your memory usage beats 26.19 % of javascript submissions (39.6 MB)

优化

var searchInsert = function (nums, target) {
    let l = 0, r = nums.length;
    while (l < r) {
        let mid = parseInt((l + r) / 2);
        if (nums[mid] < target) {
            l = mid + 1;
        } else {
            r = mid;
        }
    }
    if (nums[l] < target) return l + 1;
    else return l;
};

Accepted

  • 62/62 cases passed (76 ms)
  • Your runtime beats 75.02 % of javascript submissions
  • Your memory usage beats 27.19 % of javascript submissions (38.9 MB)