AC 3ms faster than 100% java.
1 . 我的思路
先用二分查找到target或者target不存在。
然后以此target为中心向左向右寻找边界。
AC代码如下:
class Solution {
public int[] searchRange(int[] nums, int target) {
int[] ans={-1,-1};
if(nums==null||nums.length==0)
return ans;
int i=0,j=nums.length;
int mid=-1;
while(i<=j&&j>=0&&i<nums.length){
mid=(i+j)/2;
if(nums[mid]==target)
break;
else if(nums[mid]>target)
j=mid-1;
else if(nums[mid]<target)
i=mid+1;
}
if(mid!=-1&&nums[mid]==target){
int left=mid,right=mid;
while(left>=0&&nums[left]==target)
left--;
while(right<nums.length&&nums[right]==target)
right++;
if(nums[left+1]==target&&nums[right-1]==target){
ans[0]=left+1;
ans[1]=right-1;
}
}
return ans;
}
}
2. 官方题解
整个算法的工作原理与线性扫描方法非常相似,除了用于查找最左边和最右边索引本身的子程序。
在这里,我们使用一个经过修改的二分搜索来搜索一个排序的数组,只需要做一些细微的调整。
首先,因为我们正在定位包含目标的最左(或最右)索引(而不是返回我们找到目标的真实index),
所以算法不会在找到匹配时立即终止。相反,我们继续搜索,直到lo == hi,并且它们包含一些
可以在其中找到目标的索引。
另一个变化是引入了left参数,它是一个布尔值,指示在target == nums[mid]事件中要做什么;
如果left为真,则在tie上的左子数组上“递归”。否则,我们往右走。为了理解为什么这是正确的,
考虑一下我们在索引i处找到目标的情况,最左边的目标不可能出现在任何大于i的索引处,所以我们
永远不需要考虑正确的子数组。同样的参数也适用于最右边的索引。
class Solution {
// returns leftmost (or rightmost) index at which `target` should be
// inserted in sorted array `nums` via binary search.
private int extremeInsertionIndex(int[] nums, int target, boolean left) {
int lo = 0;
int hi = nums.length;
while (lo < hi) {
int mid = (lo + hi) / 2;
if (nums[mid] > target || (left && target == nums[mid])) {
hi = mid;
}
else {
lo = mid+1;
}
}
return lo;
}
public int[] searchRange(int[] nums, int target) {
int[] targetRange = {-1, -1};
int leftIdx = extremeInsertionIndex(nums, target, true);
// assert that `leftIdx` is within the array bounds and that `target`
// is actually in `nums`.
if (leftIdx == nums.length || nums[leftIdx] != target) {
return targetRange;
}
targetRange[0] = leftIdx;
targetRange[1] = extremeInsertionIndex(nums, target, false)-1;
return targetRange;
}
}