1、基本二分查找

//常见场景:查找一个数
int binarySearch(int[] nums, int target) {
    int left = 0; 
    int right = nums.length - 1; // 注意

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

1、为什么 while 循环的条件中是 <=,而不是 < ?

答:因为初始化 right 的赋值是 nums.length-1,即最后一个元素的索引,而不是 nums.length。这二者可能出现在不同功能的二分查找中,区别是:前者相当于两端都闭区间 [left, right],后者相当于左闭右开区间 [left, right),因为索引大小为 nums.length 是越界的。

我们这个算法中使用的是前者 [left, right] 两端都闭的区间。这个区间其实就是每次进行搜索的区间,我们不妨称为「搜索区间」

2、寻找左侧边界的二分查找

//对于注意点,主要从搜索区间和终止条件方面考虑
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;
}

1、为什么 left = mid + 1,right = mid ?和之前的算法不一样?

答:因为我们的「搜索区间」是 [left, right) 左闭右开,所以当 nums[mid] 被检测之后,下一步的搜索区间应该去掉 mid 分割成两个区间,即 [left, mid)[mid + 1, right)。(搜索区间格式不变)

2、为什么该算法能够搜索左侧边界?

答:关键在于对于 nums[mid] == target 这种情况的处理:找到target值时不直接返回,而是缩小搜索上边界。

3、为什么返回 left 而不是 right

答:都是一样的,因为 while 终止的条件是 left == right

3、寻找右侧边界的二分查找

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; // 注意
}

https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/submissions/

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] index={-1,-1};
        if(nums.length<1) return index;
        int right,left;  //左右边界
        //寻找左侧边界
        int low=0,high=nums.length;
        int mid;
        while(low<high){
            mid=(low+high)/2;
            if(nums[mid]==target){
                high=mid;
            }else if(nums[mid]>target){
                high=mid;
            }else{
                low=mid+1;
            }
        }
        //没有找到直接返回(比所有数都大或者最后的数不等于目标值)
        if(low==nums.length||nums[low]!=target)
            return index;
        left=low;
        //寻找右侧边界
        low=0;high=nums.length;
        while(low<high){
            mid=(low+high)/2;
            if(nums[mid]==target){
                low=mid+1;
            }else if(nums[mid]>target){
                high=mid;
            }else{
                low=mid+1;
            }
        }
        right=low-1;

        index[0]=left;index[1]=right;          
        return index;
    }
}


algorithm      二分查找

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!