给定一个包含 n 个整数的排序数组,找出给定目标值 target 的起始和结束位置。
如果目标值不在数组中,则返回[-1, -1]
样例
给出[5, 7, 7, 8, 8, 10]
和目标值target=8
,
返回[3, 4]
挑战
时间复杂度 O(log n)
解题思路:
看到有序就用二分搜索,注意二分搜索左值和右值在边界处理上不同,特别是搜索右边界时,必须是while(l+1 < r),否则就会陷入死循环,原因是mid的值由于取(l+r)/2整数,永远偏向左方,所以搜索到最后总会l与mid重合,r在另一边。正是由于这个条件,导致最后的元素没有能加入搜索区间,所以最后需要单独处理。
public class Solution {
/**
* @param A: an integer sorted array
* @param target: an integer to be inserted
* @return: a list of length 2, [index1, index2]
*/
public int[] searchRange(int[] A, int target) {
// 前置条件判断
int[] res = {-1, -1};
if(A==null || A.length==0)
return res;
int l = 0;
int r = A.length-1;
if(A[l] > target || A[r] < target)
return res;
//二分查找左端
while(l < r){
int mid = (r+l)/2;
if(A[mid] < target)
l = mid + 1;
else if(A[mid] == target)
r = mid;
else
r = mid - 1;
}
int start = l;
//二分查找右端
l=0;
r=A.length-1;
while(l+1 < r){
int mid = (r+l)/2;
if(A[mid] < target)
l = mid + 1;
else if(A[mid] == target)
l = mid;
else
r = mid - 1;
}
int end = l;
//由于二分查找右端没有处理最后一个元素,这里特殊处理
if(end+1<A.length && A[end] == A[end+1])
end = end+1;
if(A[start]==target && A[end]==target){
res[0] = start;
res[1] = end;
}
return res;
}
}
二刷:
public class Solution {
/**
* @param A: an integer sorted array
* @param target: an integer to be inserted
* @return: a list of length 2, [index1, index2]
*/
public int[] searchRange(int[] A, int target) {
// write your code here
int[] res = {-1, -1};
if(A == null || A.length == 0 || target < A[0] || target > A[A.length-1])
return res;
//二分查找左边界
int l = 0, r = A.length-1;
while(l < r){
int mid = l + ((r-l)>>>1);
if(A[mid] < target)
l = mid + 1;
else if(A[mid] == target)
r = mid;
else
r = mid - 1;
}
if(A[l] != target)
return res;
res[0] = l;
//二分查找右边界
l = 0;
r = A.length-1;
while(l+1 < r){
int mid = l + ((r-l)>>>1);
if(A[mid] < target)
l = mid + 1;
else if(A[mid] == target)
l = mid;
else
r = mid - 1;
}
//r可能指向最后一个元素的后一个元素,所以要特殊处理
//例如查找元素8,l与mid都指向nums[4],r指向nums[5]
// 0,1,2,3,4,5
// 5,7,7,8,8,10
if(A[r] != target)
r--;
res[1] = r;
return res;
}
}