题目:
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
你可以假设数组中不存在重复的元素。
你的算法时间复杂度必须是 O(log n) 级别。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/search-in-rotated-sorted-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
-
示例 1:
输入: nums = [4,5,6,7,0,1,2], target = 0
输出: 4 -
示例 2:
输入: nums = [4,5,6,7,0,1,2], target = 3
输出: -1
分析:
所以挨个查询, O(N) 时间复杂度肯定是能完成的。 但是题上给出了条件:
其实看到 O(logN)级别 很明显就是提示你用二分法了
那么二分法对于这种不是严格意义上的递增递减数组该怎么使用呢
我们可以多举几个例子来观察。
* 比如 旋转后的数组为 5,6,7,8,1,2,3,4 middle是8 它处于5-8这个递增序列中,如果此时的target正好 5 < target < 8 那么,我们就应该在5-8这个子数组中去寻找是否包含这个值,也就是在5-8中继续使用二分法,即 right = middle - 1。 如果target不在5-8之间,那么它势必就在另一头的递增序列中,那么就left = middle + 1;
* 又比如 旋转后的数组为 4,5,6,7 1,2,3 middles是7, 它处在4,5,6,7这个递增序列中。 与上面同理
* 再比如 旋转后的数组为 5,6,7,1,2,3,4 middle是1 , 它处在1,2,3,4这个递增序列中;如果target > nums[middle] && target <= nums[len - 1] 那么 就应该在 1,2,3,4这个序列中去找,即left = middle + 1; 如果不是这样的大小关系,那么就应该 right = middle - 1;
* 所以我们需要判断 middle落在了旋转后的哪个递增序列中。在这个递增序列中再去使用二分法查找target
代码
/**
* 二分法
* 不管有序数组如何旋转,我们总能找到middle 在一个有序子数组中。
* 比如 旋转后的数组为 56781234 middle是8 它处于5-8这个递增序列中
* 又比如 旋转后的数组为 4,5,6,7 1,2,3 middles是7, 它处在4,5,6,7这个递增序列中。
* 所以我们需要判断 middle落在了旋转后的哪个递增序列中。在这个递增序列中再去使用二分法查找target
* @param nums
* @param target
* @return
*/
public static int searchDemo(int[] nums, int target) {
if (nums.length == 0 || nums == null)
return -1;
int len = nums.length;
int left = 0, right = len - 1, middle;
while (left <= right ){
middle = left - (left - right) / 2;
if(nums[middle] == target)
return middle;
//前半部分有序
if(nums[left] <= nums[middle]){
if(target < nums[middle] && target >= nums[left])
right = middle - 1;
else
left = middle + 1;
}
else {
if(target > nums[middle] && target <= nums[right])
left = middle + 1;
else
right = middle - 1;
}
}
return -1;
}