LeetCode 33, 81. Search in Rotated Sorted Array I+II
Search in Rotated Sorted Array
Binary Search的变种。由于rotated的存在,直接A[mid]<key的判断并无法解决继续搜索哪一半边。
思路是分情况,分为左半边有序还是右半边有序,再细分是继续搜索左半侧还是右半侧。由于涉及a[mid]和a[low],a[high]的比较,用闭区间比较好。
由于没有重复元素,上图 a[low]<a[mid]>a[high],下图 a[low]>a[mid]<a[high]。我们可以根据上述条件判断是左边有序还是右边有序。
class Solution { public: int search(vector<int>& a, int target) { int low=0, high=a.size()-1; //[low,high] while (low<=high){ int mid=(low+high)/2; if (a[mid]==target) return mid; if (a[low]<=a[mid]){ //left side is in order if (a[low]<=target && target<a[mid]) high=mid-1; else low=mid+1; }else{ //right side is in order if (a[mid]<target && target<=a[high]) low=mid+1; else high=mid-1; } } return -1; } };
由于mid是向下取整,其中 nums[low]==nums[mid] 归到了 nums[low]<nums[mid]。 由于没有重复的元素,nums[low]==nums[mid] 只可能在搜索区间只有两个元素的时候出现。此时,如果左边元素就是target,之前的语句就会return,因此一定不是第一个元素,low=mid+1,因此可以归到 nums[low]<nums[mid] 中。二分的边界情况还是要小心。
如果依旧向下取整,a[mid]可能等于a[low],但是a[mid]是绝对不可能等于a[high]的(除非只有一个元素时)。下面这样写就可以规避掉 a[mid]==a[high] 的可能性。对followup写起来更方便。
class Solution { public: bool search(vector<int>& a, int target) { int low=0, high=a.size()-1; //[low,high] while (low<=high){ int mid=(low+high)/2; if (a[mid]==target) return true; if (a[mid]<a[high]){ //right side is in order if (a[mid]<target && target<=a[high]) low=mid+1; else high=mid-1; }else{ //left side is in order if (a[low]<=target && target<a[mid]) high=mid-1; else low=mid+1; } } return false; } };
此外,
if (a[low]<=target && target<a[mid]) high=mid-1;
if (a[mid]<target && target<=a[high]) low=mid+1;
的符号一定要小心,如果等号位置不对,解就不在搜索区间里了。
二分时间复杂度 O(logn)
Search in Rotated Sorted Array II
虽然有重复元素在,但是思路和上一题是一样的。唯一的区别就是,当 a[mid]==a[high] 时,说明有duplicate了,我们直接 --high,反正还有 a[mid] 在,直接把high的元素去掉缩小范围继续二分即可。
class Solution { public: bool search(vector<int>& a, int target) { int low=0, high=a.size()-1; //[low,high] while (low<=high){ int mid=(low+high)/2; if (a[mid]==target) return true; if (a[mid]<a[high]){ //right side is in order if (a[mid]<target && target<=a[high]) low=mid+1; else high=mid-1; }else if (a[mid]>a[high]){ //left side is in order if (a[low]<=target && target<a[mid]) high=mid-1; else low=mid+1; }else{ // a[mid]==a[high] --high; } } return false; } };
时间复杂度 O(logn) on average,O(n) worst case.