No.33,Search in Rotated Sorted Array
这道题最喜感的是,前一天刚做完,第二天某人的面试就遇到了。
这道题把一个排好序的数组截断,把前面的一段拼到后面的一段。例如0124567变成了4567012,在这样的数组中查找一个数的index。
既然局部有序,那么这道题肯定会有O(logn)的解法。
一种方法是先找到截断点,利用二分的方式,找到某个点比它左边的小,开销为logn,再比较数组最左端和要查找的值,在相应的一段中查找,也是logn。
第二种方法实现起来更简洁,比上一种快一倍,直接开销为O(logn)。直接二分查找,只不过if的条件比较复杂。
二分后,
如果中间点和查找值相同,那么直接返回中间点的index。
如果数组最左端值小于中间点,说明还没达到截断点,此时比较中间点和查找值,如果中间点大于查找值并且查找值大于等于最左端的值,说明要查找的就在左边的一半中,再进行二分;否则说明在右边的一半中。
如果数组最左端的值大于中间点,说明已经到达截断点了,此时如果查找值大于等于最左端的值,或者查找值小于等于中间值,说明在左边的一半中,否则在右边的一半。
如果数组最左端值等于中间点,直接left++过掉最左端值。
第一种方法实现:

class Solution { public: int search(vector<int>& nums, int target) { int n=nums.size(); if(n==0){ return -1; } int pos=findPos(0,n-1,nums); cout<<pos<<endl; if(pos==0){ return binarysearch(0,n-1,target,nums); } if(nums[0]==target) return 0; else if(nums[0]>target) return binarysearch(pos,n-1,target,nums); else return binarysearch(0,pos-1,target,nums); } int findPos(int left,int right,vector<int>&nums){ if(left>right) return -1; int mid=(left+right)/2; if(nums[left]<=nums[mid]){ int pos=findPos(mid+1,right,nums); if(pos==-1){ return left; } if(nums[left]<=nums[pos]){ return left; } return pos; } else{ int pos=findPos(left,mid-1,nums); if(pos==-1){ return mid; } if(nums[pos]>nums[mid]) return mid; return pos; } } int binarysearch(int left,int right,int target,vector<int>& nums){ if(left>right) return -1; int mid=(left+right)/2; if(target==nums[mid]){ return mid; } else if(target>nums[mid]){ return binarysearch(mid+1,right,target,nums); } else return binarysearch(left,mid-1,target,nums); } };
第二种方法实现(更优):
class Solution { public: int search(vector<int>& nums, int target){ int left=0; int right=nums.size()-1; while(left<=right){ int mid=(left+right)/2; if(nums[mid]==target) return mid; if(nums[left]<nums[mid]){ if(target<=nums[mid]&&target>=nums[left]){ right=mid-1; } else left=mid+1; } else if(nums[left]>nums[mid]){ if(target>=nums[left]||target<=nums[mid]){ right=mid-1; } else left=mid+1; } else left++; } return -1; } };