题目描述:
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
你可以假设数组中不存在重复的元素。
你的算法时间复杂度必须是 O(log n) 级别。
示例 1:
输入: nums = [4,5,6,7,0,1,2], target = 0
输出: 4
示例 2:
输入: nums = [4,5,6,7,0,1,2], target = 3
输出: -1
解法1:要求logn的时间复杂度,应该是要用二分法,但是由于所给排序数组进行了一次旋转,所以不能简单的用二分法。
定义三个变量start、end、middle=(start+end)>>2,除了需判断nums[middle]与target的大小之外,还需判断nums[middle]与nums[start]、nums[end]的大小(以判断target可能存在范围是升序序列还是包含旋转点)
代码:
class Solution {
public int search(int[] nums, int target) {
int start = 0, end = nums.length-1;
while(start <= end){
if(target == nums[start]) return start;
if(target == nums[end]) return end;
int middle = (start + end)/2;
if(target == nums[middle])
return middle;
if(nums[start] > nums[middle]){
if(target > nums[middle] && nums[start] > target)
start = middle + 1;
else
end = middle - 1;
} else {
if(target < nums[middle] && target > nums[start])
end = middle - 1;
else
start = middle + 1;
}
}
return -1;
}
}
解法2:虽然用上面的解法做出来了,但是感觉太蠢了,就继续找看有没有更简洁的做法,然后找到了一位大神的做法。
序列为两个升序,给后面的升序(都小于第一个元素)加一个权值,使序列变为一个升序,然后二分查找
代码:
class Solution {
public int search(int[] nums, int target) {
int start = 0, end = nums.length-1;
while(start <= end){
int middle = (start + end) >> 1;
if(target == nums[middle]) return middle;
if(rightVal(target, nums[0]) > rightVal(nums[middle], nums[0]))
start = middle + 1;
else
end = middle - 1;
}
return -1;
}
int rightVal(int x, int start){
return x < start ? x + 0x3f3f3f3f - start : x;
}
}
附大神的博客:https://blog.csdn.net/bendaai/article/details/80059676