升序排列的整数数组 nums 在预先未知的某个点上进行了旋转(例如, [0,1,2,4,5,6,7] 经旋转后可能变为 [4,5,6,7,0,1,2] )。
请你在数组中搜索 target ,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
示例 1:
输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4
/**
因为是有序数组的旋转所以说必定有部分是有序的,我们关心的是头,中,尾三数
1 2 3 4 5(原数)
2 3 4 5 1(情况1)
mid>right [left,mid]有序
if(有序数组有有target)
right=mid
else
left=mid+1
5 1 2 3 4(情况2)
mid<right [mid,right]有序
if(有序数组有有target)
left=mid
else
right=mid-1
此时二者的收缩边界不一致
可以将(情况1)认定为[left,mid-1]为序,它的收缩情况就和(情况2相同了)。而且为了防止mid-1越界,求mid要用(left+right+1)/2
mid>right [left,mid-1]有序
if(有序数组有有target)
right=mid-1
else
left=mid
边界为(left<right)
判断left是否等于target
*/
class Solution {
public int search(int[] nums, int target) {
int len = nums.length;
if(len == 0) return -1;
int left = 0;
int right = len - 1;
int mid;
while(left< right)
{
mid = (right-left+1)/2+left;
if(nums[mid] < nums[right])
{
if(target >= nums[mid] && target <= nums[right])
left = mid;
else
right = mid - 1;
}
else
{
// [left, mid] 有序,但是为了和上一个 if 有同样的收缩行为,
// 我们故意只认为 [left, mid - 1] 有序
// 当区间只有 2 个元素的时候 int mid = (left + right + 1) >>> 1; 一定会取到右边
// 此时 mid - 1 不会越界,就是这么刚刚好
if (nums[left] <= target && target <= nums[mid - 1])
// 下一轮搜索区间是 [left, mid - 1]
right = mid - 1;
else
// 下一轮搜索区间是 [mid, right]
left = mid;
}
}
return nums[left] == target ? left : -1;
}
}