二分查找----3.在排序数组中查找元素的第一个和最后一个位置

发布于:2025-07-24 ⋅ 阅读:(22) ⋅ 点赞:(0)

 

题目链接

/**

        在一个近似递增的数组中查找指定元素,该元素可能有多个找出其出现的区间

        单次普通二分只能查到一个元素且无法确定边界;对二分改进即可

        左边界:当查到目标元素时,记录下标并将right迭代为mid-1,继续向左二分直到搜寻结束,得到左边界

        右边界:当查到目标元素时,记录下标并将left迭代为mid+1,继续向右二分直到搜寻结束,得到右边界

        即进行两次改进二分,查找左边界与右边界

        优化:

            查找左边界与右边界大量代码相同,仅left与right指针迭代逻辑不同

            添加变量boolean isLeft,控制查找方向,一个方法即可完成左、右边界的查找

*/

class Solution {
    /**
        在一个近似递增的数组中查找指定元素,该元素可能有多个找出其出现的区间
        单次普通二分只能查到一个元素且无法确定边界;对二分改进即可
        左边界:当查到目标元素时,记录下标并将right迭代为mid-1,继续向左二分直到搜寻结束,得到左边界
        右边界:当查到目标元素时,记录下标并将left迭代为mid+1,继续向右二分直到搜寻结束,得到右边界
        即进行两次改进二分,查找左边界与右边界
        优化:
            查找左边界与右边界大量代码相同,仅left与right指针迭代逻辑不同
            添加变量boolean isLeft,控制查找方向,一个方法即可完成左、右边界的查找
    */
    public int[] searchRange(int[] nums, int target) {

        //搜寻左边界
        int left = findBound(nums, target, true);
        if(left == -1) { //若为-1代表不存在该元素,无需继续搜寻
            return new int[]{-1,-1};
        }

        //搜寻右边界
        int right = findBound(nums, target, false);

        return new int[]{left, right};
    }

    private int findBound(int[] nums, int target, boolean isLeft) {
        //双指针,置于有效部分两端
        int left = 0, right = nums.length - 1;
        //不断迭代,记录已探明的边界
        int index = -1;

        while(left <= right) {
            //均分数组,缩小查找范围
            int mid = left + right >>> 1;

            //目标值在右半区,淘汰左半区
            if(nums[mid] < target) {
                left = mid + 1;
            }

            //目标值在左半区,淘汰右半区
            else if(nums[mid] > target) {
                right = mid - 1;
            }

            //查找到元素,迭代index,并依据findLeft确定查找方向
            else {
                index = mid;
                if(isLeft) { //向左继续二分,迭代right
                    right = mid - 1;
                } else { //向右二分,迭代left
                    left = mid + 1;
                }
            }
        }

        return index;
    }
}


网站公告

今日签到

点亮在社区的每一天
去签到