学算法,先从二分查找开始吧

总纲

思路很简单,细节是魔鬼。分为三个常用场景:寻找一个数,寻找左侧边界,寻找右侧边界。最后给出力扣上的题目例子。
还可以在GitHub上观看哦。AlgorithmNotes

基础框架

int binarySearch(int[] nums, int target) {
    int left = 0, right = ...;
    
    while(...) {
        int mid = (right + left) / 2;
        if (nums[mid] == target) {
            ...
        } else if (nums[mid] < target) {
            left = ...
        } else if (nums[mid] > target) {
            right = ...
        }
    }
    return ...;
}
  • 把所有情况都写清楚,展示所有细节。
  • mid = left + (right - left) / 2,防止溢出。
  • 三个框架可以合成一个,但适用面很小,不如单独的左区间或右区间使用广。

寻找一个数

int binarySearch(int[] nums, int target) {
    int left = 0;
    int right = nums.length - 1; 

    while (left <= right) {
        int mid = left + (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;
}

最基础的二分查找,每次查找都是左闭右闭区间。

  • 循环条件是 <=;
  • 更新是 left=mid+1,right=mid-1。

必要条件是数组内无重复整数。

寻找左侧边界

int left_bound(int[] nums, int target) {
    if (nums.length == 0) return -1;
    int left = 0;
    int right = nums.length;
    
    while (left < right) { 
        int mid = (left + right) / 2;
        if (nums[mid] == target) {
            right = mid;
        } else if (nums[mid] < target) {
            left = mid + 1;
        } else if (nums[mid] > target) {
            right = mid;
        }
    }
    
    return left;//此处返回left,right都可,因为相等
}

每次查找都是左闭右开区间。

  • 循环条件是 left < right;
  • 更新是 left = mid + 1, right = mid,可以理解为下一次搜索区间是 [left,mid), [mid+1,right)
  • 每次找到target时,因为存在重复数字且要找的是左边界,所以不断向左收缩, right = mid。

寻找右侧边界

int right_bound(int[] nums, int target) {
    if (nums.length == 0) return -1;
    int left = 0, right = nums.length;
    
    while (left < right) {
        int mid = (left + right) / 2;
        if (nums[mid] == target) {
            left = mid + 1; 
        } else if (nums[mid] < target) {
            left = mid + 1;
        } else if (nums[mid] > target) {
            right = mid;
        }
    }
    
    return left - 1; 
}
  • 循环条件是 left < right;
  • 更新是 left = mid + 1, right = mid,可以理解为下一次搜索区间是 [left,mid), [mid+1,right);
  • 每次找到target时,因为存在重复数字且要找的是右边界,所以不断向右收缩, left = mid + 1;
  • 返回 left - 1,因为更新时 left = mid + 1,所以循环结束时 nums[left-1] 才是target。

题目

题号 题目 链接
704 二分查找(打板题) 105265723
33 搜索旋转排序数组 105265887
35 搜索插入位置(打板题) 105265922
153 寻找旋转排序数组中的最小值 105265935
154 寻找旋转排序数组中的最小值II 105265998
162 寻找峰值 105266055
275 H指数II 105266073
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章