假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [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 可能包含重复元素。
- 这会影响到程序的时间复杂度吗?会有怎样的影响,为什么?
一、思路
假设原来升序的数组是nums,当其经过一次旋转后,得到两个升序数组nums1和nums2,由这两个升序数组构成一个旋转数组nums_rotate,假设nums1在前
那么有: n u m s 1 [ 0 ] > = n u m s 2 [ n u m s 2. s i z e ( ) − 1 ] nums1[0] >= nums2[nums2.size() - 1] nums1[0]>=nums2[nums2.size()−1]
在前面的那个数组nums1,其所有元素都大于或等于后面的数组nums2
利用这个性质可以对数组进行快速检索
(一)从target的位置开始考虑
我们知道target一定在两个数组中的一个,那么可以通过确定target的位置,来决定两边指针的移动方向。
设两个指针为lo与hi,中间的指针为mid
将数组划分为两个前一个大的数组为nums1,后一个小的数组为nums2
(1)假设target在nums1中
那么必然有: n u m s [ h i ] < = t a r g e t nums[hi]<=target nums[hi]<=target
(2)假设target在nums2中
那么必然有: n u m s [ l o ] > = t a r g e t nums[lo]>=target nums[lo]>=target
相比较于无重复的数组,有重复的最大问题是无法根据 n u m s [ l o ] nums[lo] nums[lo]和 n u m s [ h i ] nums[hi] nums[hi]来确定 n u m s [ m i d ] nums[mid] nums[mid]处在哪个数组,因此也无法制定移动策略
例如:
[1,1,5,1,1,1,1,1,1,1,1,1,1,1,1]
5
在这个例子中,我们只知道 n u m s [ m i d ] = 1 nums[mid]=1 nums[mid]=1,但是无法找出mid处于哪个有序数组
如果mid在前一个数组,那么应该改变lo
如果mid在后面的数组,那么应该改变hi
因为不知道是哪一种情况,所以同时改变lo与hi,向mid逼近
C++代码:
class Solution {
public:
bool search(vector<int>& nums, int target) {
if (nums.empty())
return false;
int lo = 0, hi = nums.size() - 1;
int mid;
while (lo <= hi) {
mid = lo + ((hi - lo) >> 1);
if (nums[mid] == target || nums[lo] == target || nums[hi] == target)
return true;
// 在前一个数组的情况
if (target > nums[lo]) {
if (target < nums[mid]) //target 在lo与mid之间
hi = mid - 1;
else {
if (nums[mid] > nums[lo]) //target 在mid与hi之间
lo = mid + 1;
else if (nums[mid] < nums[lo]) //target 在lo与mid之间
hi = mid - 1;
else {
if (nums[lo] == nums[hi]) { //target 在lo与mid之间 或者是 mid与hi之间
hi--;
lo++;
}
else
lo = mid + 1; //target 在mid与hi之间
}
}
} // 在后一个数组的情况
else if (target < nums[hi]) {
if (target > nums[mid]) //target 在mid与hi之间
lo = mid + 1;
else {
if (nums[mid] > nums[hi]) //target 在mid与hi之间
lo = mid + 1;
else if (nums[mid] < nums[hi]) //target 在lo与mid之间
hi = mid - 1;
else {
if (nums[lo] == nums[hi]) { //target 在lo与mid之间 或者是 mid与hi之间
hi--;
lo++;
}
else
hi = mid - 1; //target 在mid与hi之间
}
}
}
else
return false;
}
return false;
}
};
执行效率: