https://leetcode.com/problems/search-in-rotated-sorted-array/description/
一个递增的没有重复元素的数组,做一次移位操作,然后在数组中查找一个元素返回索引,如果没有返回-1。
首先要明白递增数组移位以后的特征,必然是前半段总比后半段大,而且各自内部是有序的。很明显这是一个特殊的二分查找。仍然是取得中间元素a[m],之后的比较过程和常规的二分不同。
以下特征是关键点:一个移位数组被a[m]切为两段,那么必然有一段是有序的,另一段是跳跃的。
我们只需要判断a[m]两侧是有序的还是跳跃的,可以判断左边,即a[low]如果小于等于a[m],说明[low,m]这段闭区间是有序的,那么[m+1, high]就是跳跃的。这里需要注意必须是有等于才行,否则如果只有两个元素,那么a[m]等于a[low],此时[low,m]这段闭区间原则上是有序的,如果不加等号,那么就会判定[m, high]是有序的,这是错误的。举个例子array = {2,1},low = 0, high = 1, m = 0。此时array[low] == array[m],那么如果不加等号判断,就会认为[low, m]是无序的,那么[m, high]是有序的,即{2,1}有序,显然错误。
接下来,是看target的值,只看左侧有序的情况,如果a[low]<=target<=a[m],那么就需要在左半边查找,否则就在右半边。我们只需要找有序的那边,只要不在有序的那段,就在跳跃段查找。如果从跳跃段下手,仍然无法确定是在左侧还是右侧。这里也需要注意必须加上等于的情况,因为我们是在一段有序闭区间里面查找。
代码:
public int search(int[] nums, int target) {
if(nums == null)
return -1;
int low = 0, high = nums.length - 1;
while(low <= high){
int m = (low + high) / 2;
if(nums[m] == target)
return m;
if(nums[low] <= nums[m]){
if(nums[low] <= target && target <= nums[m])
high = m - 1;
else
low = m + 1;
}else{
if(nums[m] <= target && target <= nums[high])
low = m + 1;
else
high = m - 1;
}
}
return -1;
}