地址:https://leetcode.com/problems/search-in-rotated-sorted-array-ii/
题目:
Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.
(i.e., [0,0,1,2,2,5,6]
might become [2,5,6,0,0,1,2]
).
You are given a target value to search. If found in the array return true
, otherwise return false
.
Example 1:
Input: nums = [2,5,6,0,0,1,2], target = 0
Output: true
Example 2:
Input: nums = [2,5,6,0,0,1,2], target = 3
Output: false
Follow up:
- This is a follow up problem to Search in Rotated Sorted Array, where nums may contain duplicates.
- Would this affect the run-time complexity? How and why?
理解:
这个题和Search in Rotated Sorted Array的区别是这里给出的数组中有重复值。会导致边界条件不太一样。
在上一题中,如果nums[mid]>nums[hi]
,就说明右边是先升后降,否则左边是先升后降。然后需要判断应该取左边的区间还是右边的区间。
实现:
因为本题中有重复,因此在一开始处理了一下重复元素。处理了之后,mid应该是不会和left还有right相等的,然后再判断
- num[mid]>nums[hi],因此右半段是先升后降
- 否则,num[mid]<num[lo],左半段是先升后降
- 否则, 从l到h是有序的,使用普通的二分查找
class Solution {
public:
bool search(vector<int>& nums, int target) {
int lo = 0, hi = nums.size() - 1;
while (lo <= hi) {
while (lo < hi&&nums[lo + 1] == nums[lo]) ++lo;
while (lo < hi&&nums[hi - 1] == nums[hi]) --hi;
int mid = lo + ((hi - lo) >> 1);
if (nums[mid] == target) return true;
if (nums[mid] > nums[hi]) {
if (target < nums[mid] && target >= nums[lo]) hi = mid - 1;
else lo = mid + 1;
}
else if (nums[mid] < nums[lo])
if (target > nums[mid] && target <= nums[hi]) lo = mid + 1;
else hi = mid - 1;
else
if (target > nums[mid]) lo = mid + 1;
else hi = mid - 1;
}
return false;
}
};
或者修改下上一题的解法,在[1, 3, 1, 1, 1]
这种形式的数组中,因为nums[lo]
、nums[mid]
以及nums[hi]
相等,导致无法根据端点判断。可以先把这种情况跳过,如下:
class Solution {
public:
int search(vector<int>& nums, int target) {
int l = 0, r = nums.size() - 1;
while (l <= r) {
int mid = l + (r - l) / 2;
if (nums[mid] == target) return true;
if (nums[l] == nums[mid] && nums[r] == nums[mid]) {
++l;
--r;
}
else if (nums[mid] > nums[r]) {
if (target > nums[mid] || target <= nums[r]) l = mid + 1; // condition for pick right side
else r = mid - 1; // else, pick left side
}
else {
if (target <= nums[r] && target > nums[mid]) l = mid + 1; // condition for pick right side
else r = mid - 1; // else, pick left side
}
}
return false;
}
};