【路飞】二分法没那么简单

296 阅读1分钟

「这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战

二分法基本模版

function binarySearch(nums, target) {
    let left  = 0, right = ...;
    while(...) {
        const mid = left + Math.floor((right - left) / 2);
        if(num[mid] == target) {
            ...
        } else if(nums[mid] < target) {
            left = ...
        } else if(nums[mid] > target) {
            right = ...
        }
    }
}

二分法哪里不简单

细节是魔鬼

  • while里到底是要用<=还是<;
  • mid到底是加一还是减一;

题目:35. 搜索插入位置

image.png

解答

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

分析:

这是一个基本的二分搜索

  1. 为什么while循环的条件是<=,而不是<?
    答:因为初始化right的赋值是nums.length-1,即最后一个元素的索引,而不是nums.length;相当于两端都闭区间[left, right],这个区间其实就是每次进行搜索的区间。
  2. 为什么是left = mid + 1和reight = mid - 1
    答:因为我们是搜索区间[left, right],当mid不是要找的target值时,下一步应该去[left, mid - 1]或[mid+1,right]里面去找。
  3. 该算法有什么缺陷?
    答:当查找数组为[1,3,3,3,4],target为3时,该算法返回的是索引2。但如果我想得到target的左边界,即索引1,或者想得到右边界,即索引3,该算法是无法处理的。