假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [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
可能包含重复元素。
这会影响到程序的时间复杂度吗?会有怎样的影响,为什么?
思路:请先参考 33.搜索旋转排序数组,https://blog.csdn.net/Scarlett_Guan/article/details/80040595。如果数组中有重复元素的情况存在的话,那么33题中,直接二分找最大值的方法就不成立了。比如说数组是2 2 2 2 0 1,或者是3 4 2 2 2 2,可能出现中心点左侧,也可能是右侧。 所以要先做一个预处理,先把两侧重复的元素截断,再按照33题中的方法去找最大值坐标。找到该点在中心点左侧或者是右侧之后,剩下的二分查找目标值的做法就是一样的了。平均时间复杂度可以达到O(logn),最坏时间复杂度O(n)。
class Solution { public: bool search(vector<int>& nums, int target) { if (nums.empty()) return false; int l = 0, r = nums.size() - 1, l1, r1, flag = -1, i; //flag记录数组中最大值坐标 while (l < r){ //预处理 if (nums[l] == target || nums[r] == target) return true; for (i = l; i <r && nums[i] == nums[i+1]; ++i);//截断左边所有重复的 l = i; for (i = r; i > l && nums[i] == nums[i-1]; --i);//截断右边所有重复的 r = i; if (nums[r] == nums[l]) --r; if (l >=r) return false; //剩下做法就和33题一样了 int mid = l + (r - l) / 2; if (nums[l] < nums[r]) break; else{ if (nums[mid] > nums[l])//分割点在中间点或者它右侧 l = mid; else if (nums[mid] <= nums[l]) //分割点在中间点左侧 r = mid - 1; } } flag = (l < r ? r : l); if (target >= nums[0]){ l1 = 0; r1 = flag; } if (target < nums[0]){ l1 = flag + 1; r1 = nums.size()-1; } while (l1 <= r1){ int mid1 = l1 + (r1 - l1) / 2; if (nums[mid1] > target) r1 = mid1 - 1; if (nums[mid1] < target) l1 = mid1 + 1; if (nums[mid1] == target) return true; } return false; } };