1、题目描述
给你一个按照非递减顺序排列的整数数组 nums
,和一个目标值 target
。请你找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target
,返回 [-1, -1]
。
你必须设计并实现时间复杂度为 O(log n)
的算法解决此问题。
2、算法思路
根据题目是一个有序的数组,并且是查找左边界和右边界,可以使用二分查找。可以有暴力法和二分法,但是暴力法本文章就不叙述了,主要讲解二分法。
3、算法流程
如果没基础的可以去看LeetCode 704.二分查找-优快云博客这篇文章
其实这题是本质就是和正常的二分查找一样,只不过在==条件下,在
寻找左边界==情况下,需要进一步减小范围,因为此时可能mid指针下的值可能是第一个出现也可能不是,他的第一次出现的值一定在[left,mid-1]
寻找右边界==情况下,需要进一步减小范围,因为此时可能mid指针下的值可能是最后一个出现也可能不是,使用需要查找的范围是[left,mid-1]
4、算法代码
class Solution {
public int[] searchRange(int[] nums, int target) {
int leftId = leftbinarysearch(nums, target);
int rightId = rightbinarysearch(nums, target);
// 检查是否找到了有效范围
if (leftId <= rightId && leftId >= 0 && rightId < nums.length && nums[leftId] == target && nums[rightId] == target) {
return new int[]{leftId, rightId};
}
return new int[]{-1, -1};
}
// 查找目标值的最左边界
public int leftbinarysearch(int[] nums, int target) {
int left = 0,right = nums.length-1;
while (left <= right){
int mid = (left + right) >>> 1;
if (nums[mid] < target){
//查找的范围是[mid+1,right]
left = mid+1;
}else if (target < nums[mid]){
//查找的范围是[left,mid-1]
right = mid-1;
}else {
//nums[mid] == target
//说明现在出现的可能不是第一次,查找范围是[left,mid-1]
right = mid -1;
}
}
return left;
}
// 查找目标值的最右边界
public int rightbinarysearch(int[] nums, int target) {
int left = 0,right = nums.length-1;
while (left <= right){
int mid = (left + right) >>>1;
if (nums[mid] < target){
//查找的范围[mid+1,right]
left = mid+1;
} else if (target < nums[mid]) {
//查找的范围是[left,mid-1]
right = mid -1;
}else {
//nums[mid] == target
//此时出现的值可能不是最后一次,查找的范围[mid+1,right]
left = mid + 1;
}
}
return right;
}
}