题目
给定一个局部有序的数组,所谓局部有序指:将一个升序排序的数组循环右移若干次。
在数组中寻找目标值 t 的索引,若存在返回其索引,不存在返回-1。
例如:
a=[4,5,6,7,0,1,2],t=1
则
结果为5
分析
一个升序排序的数组循环右移若干次后有两种情况
情况1:还是一个升序数组。
情况2:数组被分为两部分,这两部分分别升序。例如示例中的[4,5,6,7,0,1,2],可以分为两个部分[4,5,6,7]和[0,1,2],两部分各自保持升序。
一看到有关检索有序区间,大家肯定会想到二分查找。
情况1,就是朴素的二分便可,所以接下来主要分析情况2。
当我们对情况2进行二分之后,会发现有两种可能性:
1.左边有序
这个时候很明显,如果目标值t大于等于左边界且小于中间值,则二分取左半部分,否则取右半部分。
2.右边有序
这个时候很明显,如果目标值t大于中间值且小于等于有边界,则二分取右半部分,否则取左半部分。
那么如何区分左边有序和右边有序呢?这很简单。
拿情况2举例:如果左边界的值大于中间值,说明右半部分是有序的。
讨论完了这种局部有序的情况,会发现,全局有序的时候用这种方式二分也是可以的,所以我们们就可以直接用这种方式处理这个题目了。
代码
public int search(int[] nums, int target) {
int l=0,r=nums.length-1,m,t=target;
while(l<=r){
m=l+(r-l>>1);
if(target==nums[m]){
return m;
}else if(nums[l]>nums[m]){//右边有序
if(t>nums[m]&&t<=nums[r]){//答案在右边
l=m+1;
}else{
r=m-1;
}
}else{//左边有序
if(t<nums[m]&&t>=nums[l]){//答案在左边
r=m-1;
}else{
l=m+1;
}
}
}
return -1;
}
题目链接
传送门