【Leetcode】34. 在排序数组中查找元素的第一个和最后一个位置

103 阅读2分钟

题目描述

在这里插入图片描述


// 34. 在排序数组中查找元素的第一个和最后一个位置

// 给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目
// 标值在数组中的开始位置和结束位置。
// 如果数组中不存在目标值 target,返回 [-1, -1]。

// 进阶:
// 你可以设计并实现时间复杂度为 O(log n) 的算法解决此问题吗

题解

// 题目和【剑指offer】53. 数字在排序数组中出现的次数 相似,但是也不太一样,
// 本题的边界条件要棘手一些,原因是给的测试用例变化很多。
// 我们先说一下边界条件:
// 首先如果给定的target比整个数组最大的数还要大,系统认为答案不存在,
// 应该返回[-1, -1]。同理,如果给定的target比整个数组最小的数还要小,系统
// 也会认为答案不存在,返回[-1, -1]。如果给定的target在数组数值的范围内,
// 但是数组nums并没有target这个数,则认为答案不存在,返回[-1, -1]。
// 前两个情况很简单,比对nums最左和最右的数,看看target是否越界即可。
// 最后一种情况的话我们需要为此添加一个条件,如果二分查找到的left和right
// 对应的元素不等于target,则说明target并不在nums中,返回[-1, -1]。
//
// 其他思路和剑指53题相似,将res初始化为{-1, -1},如果不满足条件返回这个res,
// 定义二分查找函数binarySearch,arr[mid]大于或等于
// target right就左移,arr[mid]小于target,left就右移。
// 这样最终left会到达刚刚target序列(如果有多个target的话)最左端。
// 调用binarySearch函数搜索target,结果赋给left,再调用binarySearch函数搜索
// target并将结果赋给right。最后检查一下left和right对应元素,决定是否
// 存入res,最后返回res。
// 
// 执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
// 内存消耗:41.8 MB, 在所有 Java 提交中击败了26.75%的用户
class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] res = new int[]{-1, -1};
        if (nums.length == 0 || nums[nums.length - 1] < target || target < nums[0])
            return res;

        int left = binarySearch(nums, target);
        int right = binarySearch(nums, target + 1) - 1;
        if (nums[left] == target && nums[right] == target)
            res = new int[]{left, right};
        return res;
    }

    private int binarySearch(int[] arr, int target) {
        int left = 0;
        int right = arr.length - 1;
        int mid = 0;
        while (left <= right) {
            mid = (left + right) / 2;
            if (target <= arr[mid]) {
                right = mid - 1;
            }
            else {
                left = mid + 1;
            }
        }
        return left;
    }
}