[JS]二分查找笔记

83 阅读3分钟

二分查找

一、什么是二分法。

定义:对于区间 [a,b] 上连续不断且 f(a)· f(b)<0的函数 y = f(x),通过不断地把函数 f(x)的零点所在的区间一分为二,使区间的两个端点逐步逼近零点,进而得到零点近似值的方法叫二分法(也称为二分查找或折半查找)。(百度)

算法:当数据量很大适宜采用该方法。采用二分法查找时,数据需是排好序的。

基本思想

假设数据是按升序排序的,对于给定值 key,从序列的中间位置 k 开始比较, 如果当前位置 arr[k] 值等于 key,则查找成功;

若 key 小于当前位置值 arr[k],则在数列的前半段中查找, arr[low, mid-1];

若 key 大于当前位置值 arr[k],则在数列的后半段中继续查找 arr[mid+1, high], 直到找到为止,时间复杂度: O(log(n))

二、常用来解决什么问题

  1. 查找特定元素:在有序数组中查找特定元素的索引位置。通过反复将搜索范围缩小为一半,可以在较短的时间内快速找到目标元素或者确定其不存在。
  2. 判断元素是否存在:在有序数组中确定某个元素是否存在。如果二分查找结束时未找到目标元素,则可以确定目标元素不存在于数组中。
  3. 查找边界:找到有序数组中满足某种条件的边界,例如最小的大于等于某个值的元素的索引,或者最大的小于等于某个值的元素的索引。
  4. 求解单调函数的最值问题:对于某些特定类型的函数,例如单调递增或单调递减函数,可以利用二分法求解函数的最大值或最小值。
  5. 分治算法中的子问题的解决:在一些分治算法中,二分法常常用于解决子问题,例如快速排序中的分区操作就是利用了二分法。

总的来说,二分法适用于有序数组,并且其时间复杂度为 O(log n) ,因此对于大型数据集,二分法通常比线性搜索更加高效。

常见解法,难点

1、常见解法

例如:搜索插入位置

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

请必须使用时间复杂度为 O(log n) 的算法。 解法:三种区间方式解答。

  1. 闭区间

    // nums[i] 属于 [low, high]
    const searchInsert = (nums, target) => {
        let low = 0, high = nums.length - 1;
        while (low <= high) {
            const mid = ((high - low) >> 1) + low;
            if (nums[mid] >= target) {
                high = mid - 1; // 范围缩小到 [low, mid-1]
            } else {
                low = mid + 1; // 范围缩小到 [mid+1, high]
            }
        }
        return low; // 或者 high+1
    }
    
  2. 左闭右开区间

    // nums[i] 属于 [low, high)
    const searchInsert = (nums, target) => {
        let low = 0, high = nums.length - 1;
        while (low < high) {
            const mid = ((high - low) >> 1) + low;
            // 新区间需要包括target 
            // 区间 [low, target, mid, right] 
            if (nums[mid] >= target) {
                high = mid; // 范围缩小到 [low, mid)
            } else {
            // 区间 [low, mid, target right] 
                low = mid + 1; // 范围缩小到 [mid+1, high)
            }
        }
        return low; // 或者 high
    }
    
  3. 开区间

    // nums[i] 属于 (low, high)
    const searchInsert = (nums, target) => {
       let low = -1, high = nums.length - 1;
       while (low + 1 < high) {
           const mid = ((high - low) >> 1) + low;
           if (nums[mid] >= target) {
               high = mid; // 范围缩小到 (low, mid)
           } else {
               low = mid; // 范围缩小到 (mid, high)
           }
       }
       return low + 1; // 或者 high
    }
    

2、难点

判断单调区间,然后区间得开闭情况。在单调区间内,查找符合条件的数据。

二分法划分的新区间需要包括target,目标条件值 。

常见的二分算法问题

leetcode 题目:

  1.  搜索二维矩阵
  2. 在排序数组中查找元素的第一个和最后一个位置
  3. 搜索旋转排序数组
  4. 寻找旋转排序数组中的最小值
  5. 寻找两个正序数组的中位数

... ...

总结整理,完成。有指正欢迎友好交流,谢谢!