Description
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
).
You are given a target value to search. If found in the array return its index, otherwise return -1.
You may assume no duplicate exists in the array.
这个题目描述我强烈觉得有问题,题目中写some pivot
,注意哦pivot还没加复数形式…不过这不是重点,重点是经过我测试,实际上只会有一个转折点,并不会有多个…
Code
class Solution(object):
def search(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
if not nums:
return -1
tail = len(nums) - 1
front = 0
mid = len(nums) / 2
while front <= tail:
if nums[mid] == target:
return mid
if nums[front] == target:
return front
if nums[tail] == target:
return tail
if nums[mid] > nums[tail] and (target > nums[mid] or target < nums[tail]): #节点在右段
front = mid + 1
elif nums[tail] > nums[mid] and target > nums[mid] and target < nums[tail] : #这段是递增序列
front = mid + 1
else: #节点在左段
tail = mid - 1
mid = (front + tail) / 2
return -1
核心思想就是在普通的二分法上针对题目的要求进行修改即可,仔细列出所有情况即可解决。代码不是很简洁,不过懒得改了。
Code2 (author:lucastan)
class Solution {
public:
int search(int A[], int n, int target) {
int lo=0,hi=n-1;
// find the index of the smallest value using binary search.
// Loop will terminate since mid < hi, and lo or hi will shrink by at least 1.
// Proof by contradiction that mid < hi: if mid==hi, then lo==hi and loop would have been terminated.
while(lo<hi){
int mid=(lo+hi)/2;
if(A[mid]>A[hi]) lo=mid+1;
else hi=mid;
}
// lo==hi is the index of the smallest value and also the number of places rotated.
int rot=lo;
lo=0;hi=n-1;
// The usual binary search and accounting for rotation.
while(lo<=hi){
int mid=(lo+hi)/2;
int realmid=(mid+rot)%n;
if(A[realmid]==target)return realmid;
if(A[realmid]<target)lo=mid+1;
else hi=mid-1;
}
return -1;
}
};
这个算法首先找到了最小值的index,然后有什么用呢?重点就在int realmid=(mid+rot)%n;
这句。这个取余找到了如果递增排序,真实的中间值所在的index,这样后面的操作就和普通的二分查找没有区别了。的确聪明!
Code3
This very nice idea is from rantos22’s solution who sadly only commented “You are not expected to understand that :)”, which I guess is the reason it’s now it’s hidden among the most downvoted solutions. I present an explanation and a more usual implementation.
Explanation
Let’s say nums looks like this: [12, 13, 14, 15, 16, 17, 18, 19, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
Because it’s not fully sorted, we can’t do normal binary search. But here comes the trick:
If target is let’s say 14, then we adjust nums to this, where “inf” means infinity:
[12, 13, 14, 15, 16, 17, 18, 19, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf]
If target is let’s say 7, then we adjust nums to this:
[-inf, -inf, -inf, -inf, -inf, -inf, -inf, -inf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
And then we can simply do ordinary binary search.
Of course we don’t actually adjust the whole array but instead adjust only on the fly only the elements we look at. And the adjustment is done by comparing both the target and the actual element against nums[0].
Code
If nums[mid] and target are “on the same side” of nums[0], we just take nums[mid]. Otherwise we use -infinity or +infinity as needed.
int search(vector<int>& nums, int target) {
int lo = 0, hi = nums.size();
while (lo < hi) {
int mid = (lo + hi) / 2;
double num = (nums[mid] < nums[0]) == (target < nums[0])
? nums[mid]
: target < nums[0] ? -INFINITY : INFINITY;
if (num < target)
lo = mid + 1;
else if (num > target)
hi = mid;
else
return mid;
}
return -1;
}
这个代码也挺聪明的~
Conclusion
总的来说,这题逻辑上比较简单,重点是把所有可能情况想清楚。