LeetCode——在排序数组中查找元素的第一个和最后一个位置

Q:给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。你的算法时间复杂度必须是 O(log n) 级别。
如果数组中不存在目标值,返回 [-1, -1]。

示例 1:
输入: nums = [5,7,7,8,8,10], target = 8
输出: [3,4]

示例 2:
输入: nums = [5,7,7,8,8,10], target = 6
输出: [-1,-1]

A:
分别找左和右边界。
复习二分查找。

寻找左侧边界的⼆分查找:

因为我们初始化 right = nums.length,所以决定了我们的「搜索区间」是 [left, right),所以决定了 while (left < right)
同时也决定了 left = mid + 1 (left不可取mid)和 right = mid(right可取mid)
因为我们需找到 target 的最左侧索引,所以当 nums[mid] == target 时不要立即返回,而要收紧右侧边界以锁定左侧边界,最后相等时left=right,取[left,right)。

寻找右侧边界的⼆分查找

因为我们初始化 right = nums.length,所以决定了我们的「搜索区间」是 [left, right),所以决定了 while (left < right)
同时也决定了 left = mid + 1 和 right = mid,因为我们需找到 target 的最右侧索引,所以当 nums[mid] == target 时不要⽴即返回,⽽要收紧左侧边界以锁定右侧边界
⼜因为收紧左侧边界时必须 left = mid + 1,所以最后⽆论返回 left 还是 right,必须减⼀

代码:

    public int[] searchRange(int[] nums, int target) {
        int[] result = new int[2];
        Arrays.fill(result, -1);
        if (nums.length == 0)
            return result;
        //取出来的边界是[left,right)
        int leftRound = leftRound(nums, target);
        int rightRound = rightRound(nums, target);
        if (rightRound == 0 || leftRound == nums.length)//右边界为-1或左边界为length
            return result;
        if (nums[leftRound] != target)
            return result;
        result[0] = leftRound;
        result[1] = rightRound - 1;
        return result;
    }

    private int rightRound(int[] nums, int target) {
        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
                right = mid;
        }
        return right;//右边界取不到
    }

    private int leftRound(int[] nums, int target) {
        int left = 0, 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
                right = mid;
        }
        return left;//左边界可取到
    }

猜你喜欢

转载自www.cnblogs.com/xym4869/p/12603749.html