34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)
一、题目
给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。
示例 1:
输入:nums = [5,7,7,8,8,10], target = 8 输出:[3,4]
示例 2:
输入:nums = [5,7,7,8,8,10], target = 6 输出:[-1,-1]
示例 3:
输入:nums = [], target = 0 输出:[-1,-1]
提示:
- 0 <= nums.length <= 10^5
- -10^9 <= nums[i] <= 10^9
- nums 是一个非递减数组
- -10^9 <= target <= 10^9
二、代码
class Solution {public int[] searchRange(int[] nums, int target) {// 过滤无效参数if (nums == null || nums.length == 0) {return new int[] { -1, -1 };}// 找数组中小于target的最右下标位置,然后再加1int L = lessMostRight(nums, target) + 1;// 如果L没越界并且L位置的数等于target,就说明找到了小于target的最右边的数,并且数组中存在target// 否则数组中就没有target,直接返回(-1,-1)if (L == nums.length || nums[L] != target) {return new int[] { -1, -1 };}// 找数组中小于target + 1的最右位置int R = lessMostRight(nums, target + 1);// 返回数组中等于target的区间范围return new int[] {L, R};}// 二分,利用二分在数组arr中找到小于num的最右位置的数public int lessMostRight(int[] arr, int num) {int l = 0;int r = arr.length - 1;// 记录下标答案int ans = -1;// 二分到l和r错开结束while (l <= r) {// 取中间位置int mid = (l + r) >> 1;// 如果此时arr[mid]大于等于mid,说明还没找到小于num的数,我们再去二分到左部分去判断,看能否找到小于num的数if (num <= arr[mid]) {r = mid - 1;// 找到了一个下标位置的数小于num,就记录下这个下标为答案,看后面还能不能向右推高这个答案} else if (num > arr[mid]) {// 继续二分右部分,看后面能否推高小于num的最右下标答案l = mid + 1;ans = mid;}}return ans;}
}
三、解题思路
假设target为7,先利用二分找<7的最右位置。
如果它的下一个!=7,说明数组里没7 ,直接返回(-1,-1)。
如果<7的最右下一个==7, 说明数组中是存在7的,再利用二分找<8的最右位置,这样就找到了数组中等于7的区间的左右边界。