一、题目描述
1.1 题目
-
在排序数组中查找元素的第一个和最后一个位置
-
给定一个按照升序排列的整数数组 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]
1.2 知识点
- 二分查找
1.3 题目链接
二、解题思路
2.1 自研思路
二分查找算法的变种,该题的关键点即存在重复的待查找值,因此需要确定它的边界范围。在普通的二分查找中,当我们查找到一个符合目标值的结果时即可返回,但在该题中需要分别求得该值的左边界和右边界,因此我们可以将其分开来求,对于求左边界,当我们使用二分查找查找到目标值时,还应判断其左边的值是否也是目标值,如果其左边的值也是目标值,则证明当前搜索到的目标值不是左边界,所以我们选择继续搜索,因此 right = mid-1
,直到我们搜索到值为目标值,且该值左侧的值不为目标值时,可得该值为左边界,才可停止(对于右边界的搜索同理)。
需要注意的是边界条件的判断,当我们判断一个值是否为左边界值时需要判断它左边的值是否也为目标值,这时还需要注意一种情况就是当该值为数组下标 0 值时,此时该值左侧是没有值的,所以其必定为左边界(右边界同理)。
三、实现代码
3.1 自研实现
class Solution {
public int[] searchRange(int[] nums, int target) {
int left = 0, right = nums.length-1, mid = 0;
int[] res = new int[]{-1, -1};
// 左边界搜索
while(left <= right){
mid = left + (right-left)/2;
if(target == nums[mid] && (mid == 0 || nums[mid-1]!=target)){
res[0] = mid;
break;
}
if(target > nums[mid]) left = mid+1;
else right = mid-1;
}
left = 0;
right = nums.length-1;
// 右边界搜索
while(left <= right){
mid = left + (right-left)/2;
if(target == nums[mid] && (mid == nums.length-1 || nums[mid+1]!=target)){
res[1] = mid;
break;
}
if(target < nums[mid]) right = mid-1;
else left = mid+1;
}
return res;
}
}