二分 局部最小解

56 阅读1分钟

题目

给定一个数组,找到其中局部最小解,局部最小解定义,一定比它左右两边的数小,如果左边不存在则比右边的小,如果右边不存在则比左边的小

  • 先对边界情况进行判断,即数组的头部和尾部先判断是否是最优解,如果都不是,说明数组一定是一个左边上升,右边下降的趋势,那么中间就一定至少存在一个波谷
  • 因为一个至少存在一个波谷,所以所在的点一定在波谷的上升曲线上或者下降曲线上
  • 在上升曲线上就往左找,在下降曲线上就往右找
  • 所以二分法不一定需要有序数组,只要能满足分成两半的就行
function part(arr) {
  // 头部上升趋势
  if (arr[0] < arr[1]) {
    return 0
  }

  // 尾部下降趋势
  if (arr[arr.length - 1] < arr[arr.length - 2]) {
    return arr.length - 1
  }

  // 头部下降尾部上升趋势,期间一定存在局部最优解(一个或多个波谷),因为一定存在最低点
  // 因为一个至少存在一个波谷,所以所在的点一定在波谷的上升曲线上或者下降曲线上
  // 在上升曲线上就往左找,在下降曲线上就往右找
  let left = 1,
    right = arr.length - 2,
    mid
  // 去找比左右两边都小的数(波谷)
  while (left < right) {
    mid = (left + (right - left)) >> 1

    // 在上升曲线上,往左找
    if (arr[mid] > arr[mid - 1]) {
      right = mid - 1
    } else if (arr[mid] > arr[mid + 1]) {
      // 在下降曲线上,往右找
      left = mid + 1
    } else {
      // 找到了比左边小又比右边小的数
      return mid
    }
  }
  return mid
}