33. Search in Rotated Sorted Array
Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.
(i.e., [0,1,2,4,5,6,7]
might become [4,5,6,7,0,1,2]
).
You are given a target value to search. If found in the array return its index, otherwise return -1
.
You may assume no duplicate exists in the array.
Your algorithm's runtime complexity must be in the order of O(log n).
Example 1:
Input: nums = [4,5,6,7,0,1,2], target = 0 Output: 4
Example 2:
Input: nums = [4,5,6,7,0,1,2], target = 3 Output: -1
- 思路:题目说了复杂度要在O(logn),所以一定也是二分搜索。问题就是旋转之后怎么处理这个问题?
- 正常二分中,l < mid < r。但是经过旋转之后,mid和左右的大小是不确定的。mid和target比较之后,要往哪个区间走?如果大了,肯定往小的区间走,如果小了,肯定往大的区间走。具体向右还是向左,需要比较 l 和 r 的值之后再做决定。后来发现这个思路不太对。
- 旋转之后有两个区间,mid落在左边或者右边。
- mid落在左边区间:mid > r
- 如果target在左边 [l, mid - 1]这个单调区间之中,则继续在这个区间搜索,
- 否则在 [mid + 1, r] 这个区间搜索
- mid落在右边区间:mid < l
- 如果target在右边 [mid + 1, r ]这个单调区间,则继续在这个区间搜索
- 否则在 [l, mid - 1] 搜索
- 否则这个区间没有旋转,是个单调区间,直接用二分就好
- mid落在左边区间:mid > r
class Solution {
public:
int search(vector<int>& nums, int target) {
int l = 0, r = nums.size() - 1;
while(l <= r) {
int mid = (l + r) / 2;
if(target == nums[mid])
return mid;
// in left
if(nums[mid] > nums[r]) {
if(nums[l] <= target && target < nums[mid]) {
r = mid - 1;
} else {
l = mid + 1;
}
}
// in right
else if(nums[mid] < nums[l]) {
if(nums[mid] < target && target <= nums[r]) {
l = mid + 1;
} else {
r = mid - 1;
}
}
// no problem
else {
if(target > nums[mid])
l = mid + 1;
else
r = mid - 1;
}
}
return -1;
}
};
34. Find First and Last Position of Element in Sorted Array
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]
.
Example 1:
Input: nums = [5,7,7,8,8,10], target = 8 Output: [3,4]
Example 2:
Input: nums = [5,7,7,8,8,10], target = 6 Output: [-1,-1]
- 思路:
- start:
- 左指针只在mid<target这种确定情况下才修改
- mid > target : r = mid
- mid = target : r = mid
- mid < target : l = mid + 1
- end:
- 右指针只在mid>target这种确定情况下才修改
- mid > target : r = mid - 1
- mid = target : l = mid
- mid < target : l = mid
- start:
- 有个比较tricky的地方,在代码里说明了
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int l = 0, r = nums.size() - 1;
vector<int> ret(2, -1);
if(nums.size() == 0)
return ret;
// search for left
while(l < r) {
int mid = (l + r) / 2;
if(nums[mid] < target)
l = mid + 1;
else
r = mid;
}
if(nums[l] != target) return ret;
ret[0] = l;
r = nums.size() - 1;
// search for right
while(l < r) {
int mid = (l + r) / 2 + 1; // 让mid偏向右边
if(nums[mid] > target)
r = mid - 1;
else
l = mid; // mid会一直移动,不会死循环
}
ret[1] = r;
return ret;
}
};