力扣33.搜索旋转排序数组
原题,题目描述:

这题分类标签是二分查找,题目会给一个数组,而这个数组是一个有序数组经过部分旋转后得到的。还会给一个目标值,我们需要返回目标值在数组中的下标,如果没有这个数就返回 -1 。
思路
题目还给出了额外要求:必须在log(N)的时间复杂度下完成查找,这意味着我们不能去遍历旋转点。这题我认为在思维上其实并不简单,我也想了好一会儿。
首先题目将数组旋转过,这会导致下面的结果:
- 数组从整体看并不是有序的了,但是可以分割为两个有序数组。
- 数组第下标 0 的元素一定大于(数组只有一个元素是等于)数组最后一个元素。
基于上面两点发现,我们可以这样来解决这道题:
我们给出一个数组作为例子 [4,5,6,7,0,1,2]
题目要求时间复杂度为对数级,那我们就必须使用二分查找,二分查找我们首先初始化一个 left=0 right=len-1 mid
其中 right 是左指针,right 为右指针,mid 为中间数。
现在是如下情况:
target
↓
[4,5,6,7,0,1,2]
↑ ↑ ↑
left mid right
现在就是判断我们的目标值 target 的情况。
基于上述 1 ,整个数组可以分割出两个有序数组。我们首先判断 target 的范围,基于上述 2,首先和 right 指针的值比较,如果 target 大于 right 值,那我们可以断定值在前面的有序数组中,反之则在后面的有序数组里。然后我们就需要判断 mid 值,假设我们现在要找值 5 ,我们首先比较 mid 值和 target ,我们发现 target 比 mid 大。再比较 mid 值和 right
值,发现 mid 大于 right ,这样我们可以断定 mid 在前一个有序数组中,且在 target 右边,这意味着我们找到了一个从 left 到 mid 的有序列,那我们直接送入普通的二分查找即可找出下标。上述情况对应到右边也同样成立,所以我们已经首先解决了 target 和 mid 在同一个有序数组中的情况。下面我们看不在同一个有序数组的情况。
target
↓
[4,5,6,7,0,1,2]
↑ ↑ ↑
left mid right
假设我们要找到的值是 0 ,我们比较发现 target 和 mid 并没有在同一个有序数组,那我们就需要分情况讨论。
现在我们可以确定出来的是 mid 在前一个有序数组中, target 在后一个有序数组中,这可以根据上述 2 推出。
那这是我们就需要去比较 mid 的值,现在我们发现 mid 的值比 target 要大,并且我们在前一个数组,那我们可以直接让 le ft 等于 mid+1
mid
↓
target
↓
[4,5,6,7,0,1,2]
↑ ↑
left right
现在我们得到了新的 left 和 mid ,根据上述同理,我们直接可以判断出 left mid target 都在第二个数组中,那我们直接送入普通二分查找。其他情况基本同理
所以这道题核心就是不断的去将 mid 和 target 逼近到同一个有序数组内。那思路有了,我们的代码可以直接写出来:
代码
class Solution {
public int search(int[] nums, int target) {
int left = 0, right = nums.length - 1, mid;
if (target > nums[right] && target < nums[left]) {
return -1;
}
while (left <= right) {
mid = (left + right) / 2;
int leftValue = nums[left];
int rightValue = nums[right];
int value = nums[mid];
if (value==target){
return mid;
}
if (target > value ) {
if (target > rightValue){
if (value > rightValue) {
left = mid + 1;
} else{
right = mid - 1;
}
}else {
return search2(nums, mid+1, right, target);
}
} else {
if (target < leftValue){
if (value > rightValue) {
left = mid + 1;
} else{
right = mid - 1;
}
}else {
return search2(nums, left, mid - 1, target);
}
}
}
return -1;
}
public int search2(int[] nums, int start, int end, int target) {
int left = start, right = end, mid;
while (left <= right) {
mid = (left + right) / 2;
if (nums[mid] == target) {
return mid;
} else if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
}
}
return -1;
}
}
提交打败百分之百。时间复杂度 O(log(N)),空间复杂度O(1),完美达到题目要求达到了题目要求。
力扣33.搜索旋转排序数组
https://www.than.pw/archives/019c9097-baf7-764c-8efe-c1e200a995cd