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).
Write a function to determine if a given target is in the array.
The array may contain duplicates.
解题思路(1):题目要求我们找到具体的值,最简单的方法肯定是扫描一遍,然后就找到了,于是我们的事件复杂度是,但是放在这里肯定有更好的方法。我们可以找到转折的那个点比如4,5,6,7,0,1,2转折点是7,7左边都比4(最左边)小,7的右边都比4小。二分可以找到,找到这个点之后,后面的就好办了,我们拆成了俩个有序的数组,每一个再用二分方法来查找,最后的结果时间复杂度为
.下面我说一下如何二分找到那个关键点位置,当num[mid]对应的值比最左边值大的时候,转折点肯定在右边,那么将left改为mid+1,当num[mid]对应的值比最左边值小的时候,转折点肯定在左边,这时将right = mid-1,当等于的时候,left++,那么出来while循环,找到的就是转折点的位置.
解题思路(2):本题采用二分法实现,但是比较挠头的是边界问题,而且元素有重复,相比纯粹递增的数组难度要大得多,要解决这个问题,首先要对所有可能情况进行分类,然后对每种可能的类别进行相应的处理,本题的类别可以表示为下面的趋势图
暂且不考虑nums[mid] = nums[left]的情况,本题大致可以简化为上图两种情况,可能的情况划分出来,那么解决本题就比较容易了:
当 nums[mid] = nums[left] 时,这时由于很难判断 target 会落在哪,那么只能采取 left++
当 nums[mid] > nums[left] 时,这时可以分为两种情况,判断左半部比较简单(如果target不在左边这部分,那么我们是可以直接去掉左边这部分的)
当 nums[mid] < nums[left] 时,这时可以分为两种情况,判断右半部比较简单(如果target不在右边这部分,那么我们也是可以直接去掉右边这部分的)
C++代码如下:
作者:忆臻
链接:https://zhuanlan.zhihu.com/p/24973495
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
bool search(vector<int>& nums, int target) {
//扫描一遍肯定可以,那么放在这里不是这么简单的,是希望我们用log级别的
//方法一我们先用师兄的做法,先二分找到那个边界,然后分开进行二分查找即可~
//方法二用下面这种方法
int len = nums.size();
int left = 0,right = len-1;
while(left<=right)
{
int mid = (left+right)/2;
if(nums[mid] == target)
{
return true;
}
if(nums[mid]==nums[left])
left++;
else if(nums[mid]>=nums[left]) //砍掉的一半一定要是可以砍掉的
{
if(target<=nums[mid]&&target>=nums[left])
right = mid-1;
else
left = mid+1;
}
else
{
if(nums[mid]< target&&target<=nums[right])
left = mid+1;
else
right = mid-1;
}
}
return false;
}
};
python代码:
作者:忆臻
链接:https://zhuanlan.zhihu.com/p/24973495
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution(object):
def search(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: bool
"""
left = 0
right = len(nums)-1
while left<=right:
mid = (left + right)/2
if nums[mid] == target:
return True
if nums[mid] == nums[left]:
left +=1
elif nums[mid] > nums[left]: #这样就是有序了
if target<nums[mid] and target>=nums[left]:
right = mid-1
else:
left = mid+1
else:
if target > nums[mid] and target<=nums[right]:
left = mid+1
else:
right = mid-1
return False