前端面试算法篇——二分查找及寻找左(右)侧边界的二分查找

300 阅读1分钟

1.普通二分查找

function binarySearch(nums, target) {
  let left = 0
  let right = nums.length - 1
  while (left <= right) {
    // 使用这种写法而不使用(left+right)/2是为了防止溢出
    const mid = left + parseInt((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 -1
}

binarySearch([1, 2, 3, 4, 5], 3) // 2

2.寻找左侧边界

function bsLeftBound(nums, target) {
  let left = 0
  let right = nums.length - 1
  while (left <= right) {
    const mid = left + parseInt((right - left) / 2)
    if (nums[mid] === target) {
      right = mid - 1 // !!寻找target的极左侧,所以就算找到了target也要把区间缩小到当前位置左侧
    } else if (nums[mid] < target) {
      left = mid + 1
    } else if (nums[mid] > target) {
      right = mid - 1
    }
  }
  // !!如果nums中存在target,那么left就是它的index;如果没有且最后一位比target小,left会是nums.length(越界), 如果没有且最后一位比target大,left会是nums的最后一位
  return left === nums.length || nums[left] != target ? -1 : left
}
bsLeftBound([1, 3, 3, 3, 3, 4], 3) // 1
bsLeftBound([1, 2, 2, 2, 2, 2], 3) // -1 最终left:6, right:5 满足left === nums.length
bsLeftBound([1, 2, 2, 2, 2, 4], 3) // -1 最终left:5, right:4 满足nums[left] != target

3.寻找右侧边界

function bsRightBound(nums, target) {
  let left = 0
  let right = nums.length - 1
  while (left <= right) {
    const mid = left + parseInt((right - left) / 2)
    if (nums[mid] === target) {
      left = mid + 1 // !!寻找target的极右侧,所以就算找到了target也要把区间缩小到当前位置右侧
    } else if (nums[mid] < target) {
      left = mid + 1
    } else if (nums[mid] > target) {
      right = mid - 1
    }
  }
  // !!如果nums中存在target,那么right就是它的index;如果没有且第一位比target小,right会是nums第一位, 如果没有且第一位比target大,right会是-1
  return right < 0 || nums[right] != target ? -1 : right
}

bsRightBound([1, 3, 3, 3, 3, 4], 3) // 4
bsRightBound([2, 4, 4, 4, 4, 4], 3) // -1 最终left:1, right:0 满足nums[right] != target
bsRightBound([4, 5, 5, 5, 5, 5], 3) // -1 最终left:0, right:-1 满足right < 0