JavaScript 对 leetcode 刷题之二分查找(二)

272 阅读5分钟

模板二

使用的是 左闭右开

初始条件:left = 0;right = length

终止: left === right

向左查找的话: right = mid

向右查找: left = mid + 1

278. 第一个错误的版本

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

假设你有 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

提示:

1 <= bad <= n <= 231 - 1

来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/fi… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

/**
 * 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) {
    // 这道题目是说判断版本号是否出错
    // 然后可以通过调用接口 isBadVersion() 判断之后是否有出错
    // 如果之后有出错的话,就往前移动,如果没有出错就往后面移动
    // 是用 左闭合 右开 [)
    // 所以最后会多出一个元素
    /**
     * @param {integer} n Total versions
     * @return {integer} The first bad version
     */
    return function(n) {
        if(n == 1) return 1
        var min = 1
        var max = n
        // 如果比较小的数小于大的数就继续
        while(min < max){
            var mid = min + parseInt((max - min) / 2)
            if(isBadVersion(max) == false) {
                return max 
            }
            // 如果是没有错的话
            if(isBadVersion(mid) == false && isBadVersion(mid + 1) == true){
                return mid + 1
            }
            // 如果是正确的话,就要往前移动
            if(isBadVersion(mid) == true){
                max = mid
            }else{
                min = mid + 1
            }
        }
        // 剩余一个元素需要对其进行处理
        if(isBadVersion(min) == true){
            return min
        }
    };
};

162. 寻找峰值

这道题题目的话,我总是找不到什么时候进行向左查找和向右查找

最后看到有人发了一种解法就是利用上坡和下坡,

通过中间值和中间值的下一个值来进行判断,

如果中间值大于下一值的时候,这时候是下坡,要进行向左查找,因为峰峰值在左边

反之亦然。

峰值元素是指其值严格大于左右相邻值的元素。

给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。

你可以假设 nums[-1] = nums[n] = -∞ 。

你必须实现时间复杂度为 O(log n) 的算法来解决此问题。

示例 1:

输入:nums = [1,2,3,1] 输出:2 解释:3 是峰值元素,你的函数应该返回其索引 2。 示例 2:

输入:nums = [1,2,1,3,5,6,4] 输出:1 或 5 解释:你的函数可以返回索引 1,其峰值元素为 2; 或者返回索引 5, 其峰值元素为 6。

提示:

1 <= nums.length <= 1000 -231 <= nums[i] <= 231 - 1 对于所有有效的 i 都有 nums[i] != nums[i + 1]

来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/fi… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

/**
 * @param {number[]} nums
 * @return {number}
 */
var findPeakElement = function(nums) {
//  寻找峰值,跟上一道题目差不多,也是可以使用
// 左闭右开的方法来进行
// 这里比较难的地方就是如果最开始的比较大的话,就比较难办
// 可以使用滑坡法
    // 如果初始位置小于最后位置的大小就让
// 又明白,最后的时候左端点等于右端点
// 通过判断中间的点与中间下一个点的关系来进行判断
    var left = 0
    var right = nums.length - 1
    while(left < right){
        var mid = left + parseInt((right - left) / 2)
        // 下坡,右边进行移动
        if(nums[mid] > nums[mid + 1]){
            right = mid
        }
        // 上坡,左边右移
        else{
            left = mid + 1
        }
    }
    return left
};

153. 寻找旋转排序数组中的最小值

找到移动的条件就是判断中间的值与两边值的关系,

因为是进行旋转数组,所以具有唯一性,也就是中间的值一定会大于最右边的值或者小于最右边的值

已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到: 若旋转 4 次,则可以得到 [4,5,6,7,0,1,2] 若旋转 7 次,则可以得到 [0,1,2,4,5,6,7] 注意,数组 [a[0], a[1], a[2], ..., a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], ..., a[n-2]] 。

给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。

示例 1:

输入:nums = [3,4,5,1,2] 输出:1 解释:原数组为 [1,2,3,4,5] ,旋转 3 次得到输入数组。 示例 2:

输入:nums = [4,5,6,7,0,1,2] 输出:0 解释:原数组为 [0,1,2,4,5,6,7] ,旋转 4 次得到输入数组。 示例 3:

输入:nums = [11,13,15,17] 输出:11 解释:原数组为 [11,13,15,17] ,旋转 4 次得到输入数组。

提示:

n == nums.length 1 <= n <= 5000 -5000 <= nums[i] <= 5000 nums 中的所有整数 互不相同 nums 原来是一个升序排序的数组,并进行了 1 至 n 次旋转

来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/fi… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

/**
 * @param {number[]} nums
 * @return {number}
 */
var findMin = function(nums) {
    // 这道题目也是跟刚才那道题目是一样的就是找到峰值换成最小值
    var left = 0
    var right = nums.length - 1
    if(nums[left] < nums[right]) return nums[left]
    while(left < right){
        var mid = left + parseInt((right - left) / 2)
        // 如果中间值小于最右边的值的时候,就朝着左边查找
        if(nums[mid] < nums[right]){
            right = mid
        }else{
            left = mid + 1
        }
    }
    return nums[left] 
};

\