算法之路 第一题 力扣704. 二分查找

52 阅读2分钟

力扣题目链接

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

在看到这类题目时 只要关键字有 “有序并升序的数组” 时,用目标值查找数组是否存在并要求有返回值时 可以优先考虑二分法

下面就给大家来介绍一下 二分查找法

顾名思义 二分查找法是一种效率比较高的搜索方法 它是在有序数组中先找到中间值 公式如下

中间值 =(数组头的下标 0 + 数组尾的下标 nums.length - 1) / 2 

分成左右两份 然后中间值跟目标值进行大小比较
情况1 如果中间值 < 目标值时 这就说明 目标值在右边的数组里 这时 左边间缩小 并继续查找
情况2 如果中间值 > 目标值时 目标值在左边的数组里 这时 右边间缩小 并继续查找
情况3 如果中间值 = 目标值时 这就说明 找到了 那么就返回目标值 并结束查找

至于左边间或右边间 缩小多少 就要看循环条件了
因为要循环判断 所以使用while最为合适
至于循环条件 我一般喜欢用左闭右闭
这里科普一下 什么是左闭右闭 左闭右开
左闭右闭 [0,1] 包含0到1 就比如[0,8]表示就是0到8 包含8 用符号表示 0 <= 8
左闭右开 [0,1) 包含0 不包含1 就比如 [0,8) 表示就是0到7 不包含8 用符号表示 0 < 8
只不过左闭右闭和左闭右开的缩小边间时的写法会有很小的差别

综上所述 我们就可以写出以下代码

左闭右闭的写法
while (letf <= right) {
    let mid = (l + r) >>> 1
    if (nums[mid] > target) r = mid - 1
    else if (nums[mid] < target) l = mid + 1
    else return mid
}
左闭右开的写法
while (letf < right) {
    let mid = (l + r) >>> 1
    if (nums[mid] > target) r = mid
    else if (nums[mid] < target) l = mid + 1
    else return mid
}

左闭右闭和左闭右开 定义变量的时候也有差别

左闭右闭 
let l = 0, r = nums.length - 1
左闭右开
let l = 0, r = nums.length

本题的完整代码 如下

左闭右闭写法
var search = function(nums, target) {
    let l = 0, r = nums.length - 1
    while (l <= r) {
        let min = (l + r) >>> 0
        if (nums[min] > target) {
            r = min - 1
        } else if (nums[min] < target) {
            l = min + 1
        } else return min
    }
    return -1
};
左闭右开写法
var search = function(nums, target) {
    let l = 0, r = nums.length
    while (l < r) {
        let mid = (l + r) >>> 1
        if (nums[mid] > target) r = mid 
        else if (nums[mid] < target) l = mid + 1
        else return mid
    }
    return -1
};

此文章参考代码随想录