[Java]LeetCode. Binary Search 二分搜索

特点:被搜索序列有序;可以随机访问

二分查找一般由三个主要部分组成:

  1. 预处理 —— 如果集合未排序,则进行排序。
  2. 二分查找 —— 使用循环或递归在每次比较后将查找空间划分为两半。
  3. 后处理 —— 在剩余空间中确定可行的候选者。

1. 时间复杂度

二分搜索的时间复杂度正比于while的循环次数

循环次数 剩余元素
1 N/2
2 N/2^2
3 N/2^3
k N/(2^k)

易知,剩余元素 >=1,
最差情况是在剩余一个元素的情况下找到目标值,则有 N/(2^k) = 1
得到循环次数为k = log(2^N)
时间复杂度可表示为O(N) = O(logN)

2. 模版

Template #1:
int binarySearch(int[] nums, int target){
  if(nums == null || nums.length == 0)
    return -1;

  int left = 0, right = nums.length - 1;
  while(left <= right){
    // Prevent (left + right) overflow
    int mid = left + (right - left) / 2;
    if(nums[mid] == target){ return mid; }
    else if(nums[mid] < target) { left = mid + 1; }
    else { right = mid - 1; }
  }

  // End Condition: left > right
  return -1;
}

Exercise #1:求一个数的平方根

返回类型为 int ,开方后的小数部分略去

public int sqrt(int x) {
    if (x == 0)
        return 0;
    int left = 1, right = x;
    while (true) {
        int mid = left + (right - left)/2;
        if (mid > x/mid) {  //不能换为 mid * mid > x ,因为当 mid 过于大时,平方后会溢出
            right = mid - 1;
        } else {
            if (mid + 1 > x/(mid + 1))
                return mid;
            left = mid + 1;
        }
    }
}
Exercise #2:猜数字大小

You call a pre-defined API guess(int num) which returns 3 possible results (-1, 1, or 0):

-1 : My number is lower
 1 : My number is higher
 0 : Congrats! You got it!
public class Solution extends GuessGame {
    //My" means the number which is given for you to guess not the number you put into guess(int num).
    public int guessNumber(int n) {
        if(guess(n) == 0) return n;
        int left = 1, right = n;
        while(left <= right){
            int mid = left + (right - left)/2;
            if(guess(mid) == 0) return mid;
            else if(guess(mid) == -1) right = mid - 1;
            else left = mid + 1;
        }
        return -1;
    }
}
Exercise #3:搜索旋转排序数组

0 1 2
6 7 0
7 0 1

  1. 因为 Binary Search 需要在获得中间数后,判断下一次是搜索左半段还是右半段,可以用 mid 值和 right 值比较:
    mid 值 < right 值 说明右半段;否则,左半段有序;
  2. 在有序的半段中判断目标值是否在此区域内,以确定要保留哪边。
public int search(int[] nums, int target) {
        if(nums == null || nums.length == 0) return -1;
        int left = 0, right = nums.length - 1;
        while(left <= right){
            int mid = left + (right - left) / 2;
            if(nums[mid] == target) return mid;
            else if(nums[mid] < nums[right]){  //右半段有序
                if(nums[mid] < target && nums[right] >= target) left = mid + 1;
                else right = mid - 1;
            }else{
                if(nums[mid] > target && nums[left] <= target) right = mid - 1;
                else left = mid + 1;
            }
        }
        return -1;
    }


Template #2:

左闭右开区间:right = nums.length, right = mid

int binarySearch(int[] nums, int target){
  if(nums == null || nums.length == 0)
    return -1;

  int left = 0, right = nums.length;
  while(left < right){
    // Prevent (left + right) overflow
    int mid = left + (right - left) / 2;
    if(nums[mid] == target){ return mid; }
    else if(nums[mid] < target) { left = mid + 1; }
    else { right = mid; }
  }

  // Post-processing:
  // End Condition: left == right
  if(left != nums.length && nums[left] == target) return left;
  return -1;
}

你可能感兴趣的:([Java]LeetCode. Binary Search 二分搜索)