二分学了挺久了,但还是没有掌握,果然还是太菜了,今天做了一个力扣里面的<查找旋转排序数组>,做的有点艰难,写篇文章加深一下记忆吧
题目:
整数数组 nums 按升序排列,数组中的值 互不相同 。
在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。
给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。
示例 1:
输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4
示例 2:
输入:nums = [4,5,6,7,0,1,2], target = 3
输出:-1
示例 3:
输入:nums = [1], target = 0
输出:-1
提示:
1 <= nums.length <= 5000
-10^4 <= nums[i] <= 10^4
nums 中的每个值都 独一无二
题目数据保证 nums 在预先未知的某个下标上进行了旋转
-10^4 <= target <= 10^4
进阶:你可以设计一个时间复杂度为 O(log n) 的解决方案吗?
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/search-in-rotated-sorted-array
解读:
首先我们知道这个数组本身就是一个递增且不重复的序列,当这个序列翻转后,也就是切割前面一部分序列再拼接到序列后面,因此这个数组在某个点上断开成两部分,这两部分仍是两个递增序列。
当然也许有人会问先找那个旋转的点不就好了吗,但据力扣题目描述那样,这个题属于二分并且进阶要求要时间复杂度为O(log n),这时要是直接查找旋转的点,要是用朴素的暴力查找时间复杂度就已经时O(n)了,用二分那光查找旋转点就是O(log n),这可不行。
据题意,我们试着用二分的思想,设置一个中心位置的指针 mid 时,我们很容易发现一个现象
图:
当我们根据中心位置分为两个序列看的时候,会发现一定有一个部分是严格递增序列,因此,我们便可以根据二分查找原理,将序列分为两个部分。
如果目标值在有序序列中,我们就可以按照二分法去查找,如果不在有序序列中,那就将非递增序列再分为有序跟无序两个部分,接着重复操作,直到找到为止,如果实在找不到,就说明不存在。
那怎么用二分判断哪个序列是有序呢,又如何判断目标值在哪个区间呢,我们不要忘了,这个序列原本就是严格递增的序列,以图中第一个例子为例,我们中心指针的值nums[mid]如果大于序列头nums[0],那nums[mid]一定是区间[ 0 , mid ]中的最大值,而我们拼接到序列后面的那一段序列,其中每一个值都会小于nums[0],根据判断目标值是否大于等于nums[0]小于nums[mid]就可以知道在哪个区间了,同理,如图中第三个例子,中心值小于nums[0],足以证明区间[mid , nums.length-1]是严格递增序列。
接下来上代码
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
//因为是自己测试,需要自己手动输入序列
Main m = new Main();
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int[] nums = new int[n];
//首先实现一下输入数组内容 注意:内容一定要严格符合题意
//1.不能有重复元素
//2.保证在某个位置上进行旋转,在此位置两边都是严格递增的数列
for(int i = 0 ; itarget){
//符合两个条件说明目标值在左区间
right = mid - 1;//区间向左缩小
}else{
//只符一个条件或都不符合 说明目标值在 下标mid后面的非递增区间中
left = mid + 1;//区间向右缩小
}
}else{
//下标mid-len-1的位置为有序
if(nums[len-1]<= target && nums[mid]



