彻底搞懂并记住二分搜索

169 阅读2分钟

直接上代码

public class BinarySearch {
    /*
        二分搜索的注意点有:
        1、左右下标的取值范围,会有 r = nums.length 和 r = nums.length - 1 两种写法
        2、循环结束条件,会有 l < r 和 l <= r 两种写法,决定是否在循环结束补充判断
        3、根据二分搜素的目的不同,在更新l和r时会有不同
        4、为了我自己的记忆不混乱,统一采用 int l = 0, r = nums.length - 1 和 while(l <= r) 写法
     */

    // 顾名思义,找到第一次碰到的目标值位置下标,如果不存在目标值返回-1
    public int firstBinarySearch(int[] nums, int target){
        int l = 0, r = nums.length - 1;
        // 一般用,l<=r,这样不用再循环结束时对nums[l]进行判断
        while(l <= r){
            int m = l + (r - l) / 2;
            if(nums[m] == target){
                return m;
            }else if(nums[m] < target){
                l = m + 1;
            }else {
                r = m - 1;
            }
        }
        // 循环内无返回,即没找到
        return -1;
    }

    // 顾名思义,找到最左边目标值位置下标,如果不存在目标值返回-1
    public int leftBinarySearch(int[] nums, int target){
        int l = 0, r = nums.length - 1;
        // 一般用,l<=r,这样不用再循环结束时对nums[l]进行判断
        while(l <= r){
            int m = l + (r - l) / 2;
            if(nums[m] == target){
                // 如果已经找到了目标值,因为要找最左边的,将右指针移动过来,向左搜索
                // 为了结束死循环,使r = m - 1,而不是r = m
                r = m - 1;
            }else if(nums[m] < target){
                l = m + 1;
            }else {
                r = m - 1;
            }
        }
        // 因为循环内无返回语句,要在结束时判断情况
        if(l == nums.length)//情况2
            return -1;
        return nums[l] == target ? l : -1;
    }

    // 顾名思义,找到最右边目标值位置下标,如果不存在目标值返回-1
    public int rightBinarySearch(int[] nums, int target){
        int l = 0, r = nums.length - 1;
        // 一般用,l<=r,这样不用再循环结束时对nums[l]进行判断
        while(l <= r){
            int m = l + (r - l) / 2;
            if(nums[m] == target){
                // 如果已经找到了目标值,因为要找最右边的,将左指针移动过来,向右搜索
                // 为了结束死循环,使l = m + 1,而不是l = m
                l = m + 1;
            }else if(nums[m] < target){
                l = m + 1;
            }else {
                r = m - 1;
            }
        }
        if(l == 0)
            return -1;
        return nums[l - 1] == target ? l - 1 : -1;
    }
}

总结:左右边界的二分搜索,无非是在遇到目标值时向左向右收缩边界而不是直接返回,不直接返回我们则要在循环结束对当前情况进行判断返回什么,同时还要去判断指针是否越界;循环结束的条件是r+1=l;只要明确各种情况做好边界处理就能正确写出代码。