二分查找法- 寻找边界

寻找左右边界, 其实本质是解决数组中如果有重复元素的时候, 如果数组中本身不存在目标值, 两个方法寻找到的边界是一样的, 都是第一个大于目标值的数.

如果存在目标值, 并且存在多个, 那么左侧边界就是寻找到多个目标值的第一个, 右侧边界就是寻找到多个目标值的最后一个.

寻找右侧边界的写法

目标

例如

情况1: 数组[1, 2, 5, 5] 中寻找4, 那么返回索引2

情况2: 数组[1, 2, 3, 4, 6, 7, 8]寻找5, 返回索引4

情况3: 数组[1, 2, 3, 3, 5, 6, 7]寻找3, 返回索引3

情况4: 数组[1, 2, 5, 5] 中寻找5, 返回索引3

即数组中比target大的第一个数的索引

写法

二分查找的写法

    int right_bound(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) {
                left = mid + 1;
            } else if (nums[mid] > target) {
                right = mid - 1;
            } else if (nums[mid] == target) {
                // 别返回,锁定右侧边界
                left = mid + 1;
            }
        }
        return right;
    }
复制代码

为什么这么写?

常规写法和二分查找一样, 需要注意1个地方的写法

  1. 当mid指针当元素和目标元素相等时, 锁定右边界, 继续移动左指针, 这样左右指针相遇的时候, 要么是第一个比target大的元素, 要么是最后一个和target相等的元素

寻找左侧边界的写法

目标

例如

数组数组[1, 2, 5, 5] 中寻找4, 那么返回索引2

情况2: 数组[1, 2, 3, 4, 6, 7, 8]寻找5, 返回索引4

情况3: 数组[1, 2, 3, 3, 5, 6, 7]寻找3, 返回索引2

情况4: 数组[1, 1, 1, 2, 5, 5] 中寻找1, 返回索引0

即数组中比target小的第一个数的索引

写法

二分法写法:

    int left_bound(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) {
                left = mid + 1;
            } else if (nums[mid] > target) {
                right = mid - 1;
            } else if (nums[mid] == target) {
                // 别返回,锁定左侧边界
                right = mid - 1; // 注意
                }
        }
        return left;
    }
复制代码

为什么这么写?

大体写法和二分查找的写法一致, 需要注意1个地方

  1. 当mid指针当元素和目标元素相等时, 锁定左边界, 移动右边界. 这样左右指针重合的位置, 一定是第一个大于等于target的目标元素
分类:
阅读
标签: