题目描述
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,0,1,2,2,5,6] 可能变为 [2,5,6,0,0,1,2] )。
编写一个函数来判断给定的目标值是否存在于数组中。若存在返回 true,否则返回 false。
示例 1:
输入: nums = [2,5,6,0,0,1,2], target = 0
输出: true
示例 2:
输入: nums = [2,5,6,0,0,1,2], target = 3
输出: false
进阶:
这是 搜索旋转排序数组 的延伸题目,本题中的 nums 可能包含重复元素。
这会影响到程序的时间复杂度吗?会有怎样的影响,为什么?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/search-in-rotated-sorted-array-ii
思路
在一个经过了循环移位的有序数组(可能有重复元素)里进行查找,在有序数组里进行查找,肯定二分。
这题和33. Search in Rotated Sorted Array其实是类似的,唯一不同就是此题可能有重复元素。
但是基本思路不变,参考33题题解思路二,
我们得到一个重要的想法:二分后左右两半至少有一半是有序的。所以我们可以判断target是否在这有序的一半,若在则丢弃掉另一半进入下一次循环,若不在则丢弃掉有序的这一半进入下一次循环。
那么如何判断哪一半是有序的呢?分为以下几种情况:
- 若
nums[mid] == target
,则返回true即可。 - 若
nums[low] < nums[mid]
,则左半边一定有序; - 若
nums[low] > nums[mid]
,则右半边一定有序; - 否则,我们无法判断到底哪一边有序,但是可以肯定的是
nums[low] != target
,所以此时我们直接low++
然后进入下一循环。
最坏的情况就是数组中元素全相等且不等于target,此时时间复杂度为O(n)
空间复杂度O(1)
C++
class Solution {
public:
bool search(vector<int>& nums, int target) {
int mid, low = 0, high = nums.size() - 1;
while(low <= high){
mid = (high - low) / 2 + low;
if(nums[mid] == target) return true;
if(nums[low] < nums[mid]){
if(nums[low] <= target && target < nums[mid]) high = mid - 1;
else low = mid + 1;
}
else if(nums[low] > nums[mid]) {
if(nums[mid] < target && target <= nums[high]) low = mid + 1;
else high = mid - 1;
}
else low++;
}
return false;
}
};
class Solution {
public:
bool search(vector<int>& nums, int target) {
int first = 0, last = nums.size();
while(first != last){
const int mid = first + (last - first)/2;
if(target == nums[mid]) return true;
if(nums[first] < nums[mid]){
if(nums[first] <= target && target < nums[mid])
last = mid; // [first, mid)
else
first = mid + 1; // [mid + 1, last)
}else if(nums[first] > nums[mid]){
if(nums[mid] < target && target <= nums[last-1])
first = mid + 1; //[mid + 1, last)
else
last = mid; //[first, mid)
}else{
// skip duplicate one 极端形式[1,1,1,1,1] 中寻找2
first ++;
}
}
return false;
}
};