34. Search for a Range
原题:
Given an array of integers nums sorted in ascending order, find the starting and ending position of a given target value.Your algorithm’s runtime complexity must be in the order of O(log n).
If the target is not found in the array, return [-1, -1].
(给定一个升序数组,找到目标值的起始位置和结束位置。时间复杂度需为O(log n)。 如果目标值没找到,返回 [-1, -1] )思路一:
在有序数组中查找值,首先想到的就是二分查找,但是这道题是需要找到起始位置和结束位置。那么也很容易想到,我通过二分查找找到目标值后,然后以当前目标值的下标为终点,继续向前查找目标值,如此循环直到二分查找没有找到为止。同理,结束位置也是如此的思路。
AC解一
class Solution {
public int[] searchRange(int[] nums, int target) {
int len = nums.length, start = 0, end = len - 1;
int min, max;
min = max = find(nums, start, end, target);
while(true) {
int minS = find(nums, start, min - 1, target);
if( minS == -1) break;
else min = minS;
}
while(true) {
int maxL = find(nums, max + 1, end, target);
if( maxL == -1) break;
else max = maxL;
}
return new int[]{min, max};
}
private int find(int[] nums, int start, int end, int target) {
while(start <= end) {
int mid = (start + end) / 2;
if(target == nums[mid]) return mid;
else if(target > nums[mid]) start = mid + 1;
else end = mid - 1;
}
return -1;
}
}
- 思路二:
对二分查找做个变种。当找到目标值时不急着立马返回下标,而是继续向前查找直到找到最小值。其中的关键点就是将小于等于目标值这两种情况合并起来判断,并让 end = mid,而不再是 end = mid - 1,因为此时 target <= nums[mid] ,所以你无法将 end = mid - 1。
其实就是对思路一的简化。至于最大下标则是查找比目标值大1的数的下标减1 ,即 find(nums, target + 1) - 1。
AC解
class Solution {
public int[] searchRange(int[] nums, int target) {
int s = find(nums, target);
if(s == nums.length || nums[s] != target) return new int[]{-1, -1};
if(s == nums.length - 1) return new int[]{s, s};
return new int[]{s, find(nums, target + 1) - 1};
}
private int find(int[] nums, int target) {
int start = 0, end = nums.length;
while(start < end) {
int mid = (end + start) / 2;
if(target > nums[mid]) start = mid + 1;
else end = mid;
}
return start;
}
}