左神算法笔记-二分搜索

101 阅读2分钟

有序数组中是否存在一个数字

普通的二分搜索

public static boolean exist(int[] arr, int num) {
   if (arr == null || arr.length == 0) {
      return false;
   }
   int l = 0, r = arr.length - 1, m = 0;
   while (l <= r) {
      m = (l + r) / 2;
      if (arr[m] == num) {
         return true;
      } else if (arr[m] > num) {
         r = m - 1;
      } else {
         l = m + 1;
      }
   }
   return false;
}

两个变种

有序数组中找>=num的最左位置

public static int findLeft(int[] arr, int num) {
   int l = 0, r = arr.length - 1, m = 0;
   int ans = -1;
   while (l <= r) {
      m = l + ((r - l) >> 1);
      // 中点大于等于 num,记录答案往左二分
      if (arr[m] >= num) {
         ans = m;
         r = m - 1;
      } else {
          // 不记录答案往右二分
         l = m + 1;
      }
   }
   return ans;
}

有序数组中找<=num的最右位置

public static int findRight(int[] arr, int num) {
   int l = 0, r = arr.length - 1, m = 0;
   int ans = -1;
   while (l <= r) {
      m = l + ((r - l) >> 1);
      // 中点小于等于 num,记录答案往右二分
      if (arr[m] <= num) {
         ans = m;
         l = m + 1;
      } else {
         // 不记录答案往左二分
         r = m - 1;
      }
   }
   return ans;
}

二分搜索不一定只发生在有序数组

某侧必有或者某侧没有,可以考虑二分

寻找峰值问题

public int findPeakElement(int[] nums) {
    int n = nums.length;
    if (nums.length <= 1) {
        return 0;
    }
    // 因为默认 nums[-1] = nums[n] = -∞
    // 所以只要第一个位置的数值大于第二个位置的数值,返回 1
    // 倒数第一个位置的数值大于倒数第二个位置的数值,返回n-1 即可
    if (nums[0] > nums[1]) {
        return 0;
    }
    if (nums[n - 1] > nums[n - 2]) {
        return n - 1;
    }

    // X ↗   中间一定有峰值点   ↘   X
    // 0 1                  n-2 n-1
    int left = 1, right = n - 2,mid=0, ans = -1;
    while (left <= right) {
        mid = left + (right - left) / 2;
        // 左边值大于中间值,峰值存在于左侧,左侧二分
        if (nums[mid] < nums[mid - 1]) {
            right = mid-1;
        } else if ( nums[mid] < nums[mid + 1]) {
            // 右边值小于中间值,峰值存在于右侧,右侧二分
            left = mid+1;
        }else {
            // 中间值是峰值
            ans = mid;
            break;
        }
    }
    return ans;
}

二分答案法

todo