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.
这一题,直接遍历数组也是可以的,这是最差的一种做法,题目给的排序条件就用不上了。如果先找出旋转的位置,效果也一样,还不如直接找,都是o(n)。
因为题目说排序数组,很容易想到使用二分法。、
特点:
旋转以后,数组可以看成两部分,左边部分大于右边部分。
具体来说,假设数组是A,每次左边缘为l,右边缘为r,还有中间位置是m。在每次迭代中,分三种情况:
(1)如果target==A[mid],那么mid就是我们要的结果,直接返回;
(2)如果A[m]>=A[left],那么说明从left到mid一定是有序的(没有受到rotate的影响),那么我们只需要判断target是不是在left到mid之间,如果是则把右边缘移到m-1,否则就target在另一半,即把左边缘移到m+1。
(3)如果A[m]<A[left],那么说明从mid到right一定是有序的,同样只需要判断target是否在这个范围内,相应的移动边缘即可。
根据以上方法,每次我们都可以切掉一半的数据,所以算法的时间复杂度是O(logn),空间复杂度是O(1)。代码如下:
class Solution { public int search(int[] nums, int target) { if(nums==null||nums.length==0) return -1; int left=0; int right=nums.length-1; while(left<right){ int mid=(left+right)/2; if(nums[mid]==target) return mid; //因为最终移动left和right都是根据mid的值,所以先判断mid在哪半部分,先确定mid //如果mid在左边..mid有可能会等于left的 if(nums[mid]>=nums[left]){ //如果target在left和mid中间,就移动right,若target在mid右边(可能在左半部分,也有可能在右半部分),就移动left if(nums[left]<=target&&nums[mid]>target) right=mid-1; else left=mid+1; }else{ if(nums[right]>=target&&target>nums[mid]) left=mid+1; else right=mid-1; } } //最后left和right重合 return nums[left]==target?left:-1; } }