出处
《算法》1.4.20
33. 搜索旋转排序数组 https://leetcode-cn.com/problems/search-in-rotated-sorted-array/
81. 搜索旋转排序数组 II https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/
153. 寻找旋转排序数组中的最小值 https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/
154. 寻找旋转排序数组中的最小值 II https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array-ii/
都是衍生的相似题目,33题对应《算法》上面的1.4.20
算法上的题目
和 https://leetcode-cn.com/problems/peak-index-in-a-mountain-array/ 852. 山脉数组的峰顶索引
这一题很像,可以参考之前写的答案:https://blog.youkuaiyun.com/hhmy77/article/details/108193937
33. 搜索旋转排序数组
1 暴力
暴力法很容易写出,但是算法级别是 O ( N ) O(N) O(N),不符合题意
class Solution {
public int search(int[] nums, int target) {
if(nums==null){
return -1;
}
for(int i=0;i<nums.length;i++){
if(nums[i]==target){
return i;
}
}
return -1;
}
}
2 二分
原数组不是递增的,但是是通过递增数组旋转回来的,如果能找到这个旋转的点,将数组旋转成递增数组,那么就能使用二分了
或者我们再找到这个数组的分界点的时候,分别对左右两个部分做二分,然后判断target在不在这两个部分里面也行
但是编写代码的过程中发现直接二分找peak似乎不太好找,所以先用
O
(
N
)
O(N)
O(N)算法来找peak,然后再对两个部分进行二分搜索,下面代码是AC的
时间复杂度由于有一个
O
(
N
)
O(N)
O(N)级别的算法,所以下面做法不是最优的
class Solution {
public int search(int[] nums, int target) {
// 特殊判断
if(nums.length==1){
if(nums[0]==target)
return 0;
else
return -1;
}
int peak = findPeak(nums);
int left=b_search(nums,0,peak,target);
int right=b_search(nums,peak+1,nums.length-1,target);
// System.out.println(peak+" "+left+" "+right);
if(left!=-1)
return left;
if(right!=-1)
return right;
return -1;
}
public int findPeak(int[] nums){
int i=0;
for(;i<nums.length-1;i++){
if(nums[i]>nums[i+1])
break;
}
return i;
}
public int b_search(int[] nums,int lo,int hi,int target){
while(lo<=hi){
int mid=(lo+hi)/2;
if(nums[mid]==target){
return mid;
}else if(nums[mid]>target){
hi=mid-1;
}else{
lo=mid+1;
}
}
return -1;
}
}
接下来尝试写出用二分来findPeak,但是这里我还不会做,不能直接照搬山脉数组的写法,因为这题里面会有两个peak,而我们需要找的是最大的那个peak,所以如果我们直接二分的话,只会找到一个peak,它可能是最大值,也可能不是,只有用最大值的peak来划分,接下来才能得到正确的二分结果,可能需要递归来