【算法入门】二分查找

203 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第8天,点击查看活动详情

前言

二分查找是一种在有序数组中查找某一特定元素的搜索算法,在很多人的印象里,二分查找是一种比较简单的算法,然而在实际做题中,二分查找经常容易写错,特别是在处理边界条件的时候,今天我们就来聊一聊二分查找,看能不能找到一种比较简单,通用的方法来解决大部分的二分查找问题

先看一个例子

先给定一个数组

const list = [1, 2, 3, 5, 5, 5, 8, 9]

思考下面4个问题

  • 找到第一个 >=5 的元素
  • 找到最后一个 <5 的元素
  • 找到第一个 >5 的元素
  • 找到最后一个 <=5 的元素

先简单想想来看下答案

2022-11-28 23 13 19

以上其实就是我们在使用2分查找时经常会遇到的各种边界问题,而对于边界问题的处理,常常决定着最终结果的准确

如何分析问题

对于二分查找的问题,都可以抽象为在一个有序数组中寻找边界,以下以寻找蓝,红方块边界为例,最开始拿到数组是白色的,通过一次又一次的查找,去扩大蓝色 (左指针右移 left + 1) 和红色区域 (右指针左移 right - 1) ,最终找到边界 (即求出未知数K)

2022-11-28 23 17 18

解题模板

大家来看一段伪代码

left = -1, right = n
​
while left + 1 != right
    m = (left + right) / 2
    if IsBlue(m) 
        left = m
    else
        right = m
        
return left or right

做一道 leetCode 题

704. 二分查找 - 力扣(LeetCode)

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

分析

二分查找都可以看做找边界 target 的问题,本题 left 左区域的值都小于 target (即蓝色区域) ,右边界的值都大于 target (即红色区域) ,而等于时即求出边界

解题

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var search = function(nums, target) {
    let left = -1
    let right = nums.length
​
    while(left + 1 != right) {
        let middle = (left + right) >> 1 // 使用 >> 位运算代替除法避免小数
        if (nums[middle] == target) {
            return middle
        }
        if (nums[middle] > target) {
            right = middle
        }
        if (nums[middle] < target) {
            left = middle
        }
    }
​
    return -1 
};

怎么样,大家可以试试用这个解题模板去试试,看是否能让你做二分查找相关的题目时准确率更高些 ^-^