目录
- 题目
- 1-思路
- 1-1 模式识别:
- 1-2 二分模板 && 本质
- 二分红色边界
- 二分绿色边界
- 1-3 本题思路
- ①二分出第一个区间
- ②判断 target 在哪个区间
- ③利用二分性质
- 2- 实现
- ⭐33. 搜索旋转排序数组——题解思路
- 3- ACM实现
题目
- 原题连接:33. 搜索旋转排序数组
- 参考视频:B站教学视频
1-思路
1-1 模式识别:
- 模式1 ——>
**O(log n)**
:使用O(log n)
时间复杂度算法查找到目标值,因此想到的算法是二分算法。 - 模式2 ——> 旋转数组:旋转数组无法通过一次二分找到目标值,因此需要两次二分。
1-2 二分模板 && 本质
- 根据二分查找的过程,二分模板分两种情况。
- 一种是二分出 红色边界
target / x
,条件为q[mid]<=x
——>mid = (l+r+1)/2
- 一种是二分出 绿色边界
target / x
,条件为q[mid]>=x
——>mid = (l+r)/2
- 一种是二分出 红色边界
二分红色边界
- 结果收集
r
while(l<r){int mid = (l+1+r)/2;if(q[mid]<=x) l=mid;else r = mid-1;
}
二分绿色边界
- 结果收集
l
while(l<r){int mid = (l+r)/2;if(q[mid]>=x) r=mid;else l = mid+1;
}
- 二分的本质在于让 二分的区间满足一个性质。
1-3 本题思路
- 本题提供的旋转数组的分布如下,因此需要分别使用两次二分
①二分出第一个区间
-
- 答案区间
l = 0, r = nums.length-1
- 答案区间
-
- 利用二分性质,使得 前半段的性质 满足
nums[mid] >= nums[0]
,二分出旋转点
- 利用二分性质,使得 前半段的性质 满足
-
- 区间划分
- 若满足
nums[mid] >= nums[0]
此时 答案肯定在[mid,r]
中 - 否则答案在
[0,mid-1]
中,因为是r = mid-1
,此时 mid 初始化为mid=(l+r+1)/2
// 1. 第一次二分找出 分界点// 二分本质,找到前半段 满足 nums[mid] >= nums[0]int l = 0,r = nums.length-1;while(l<r){int mid = (l+r+1)/2;if(nums[mid] > nums[0]) {l = mid;}else {r = mid-1;}}
②判断 target 在哪个区间
// 2.判断二次二分边界if(target >= nums[0]) {l = 0;}else {l=r+1 ;r = nums.length-1;}
③利用二分性质
// 3.第二次二分while(l<r){int mid = (l+r+1)/2;if(nums[mid]<=target) l=mid;else r = mid-1;}return nums[r] == target ? r:-1;
2- 实现
⭐33. 搜索旋转排序数组——题解思路
:::info
- 1. 利用二分性质,二分出分界点
- 二分本质是使得一个区间满足性质
- 首次二分使得
**nums[mid]**
满足**nums[mid]>=nums[0]**
的性质 **if(nums[mid] >= nums[0])**
此时 结果在**[mid,r]**
因此 ——>**l = mid**
- 否则
r = mid-1
,根据判断**mid =(l+r+1)/2**
- 2. 利用边界找出二次二分边界
**if(target >= nums[0]) ——> l = 0;**
**else l = mid+1; r = nums.length-1**
- 3. 二次二分
- 利用二分红色边界模板
:::
- 利用二分红色边界模板
class Solution {public int search(int[] nums, int target) {// 1. 第一次二分找出 分界点// 二分本质,找到前半段 满足 nums[mid] >= nums[0]int l = 0,r = nums.length-1;while(l<r){int mid = (l+r+1)/2;if(nums[mid] > nums[0]) {l = mid;}else {r = mid-1;}}// 2.判断二次二分边界if(target >= nums[0]) {l = 0;}else {l=r+1 ;r = nums.length-1;}// 3.第二次二分while(l<r){int mid = (l+r+1)/2;if(nums[mid]<=target) l=mid;else r = mid-1;}return nums[r] == target ? r:-1;}
}
3- ACM实现
public class findTraversalNums {public static int findT(int[] nums,int target){int l = 0 , r = nums.length;// 1.首次二分while(l<r){int mid = (l+r+1)/2;if(nums[mid] >= nums[0]) l=mid;else r=mid-1;}// 2. 划分区间if(target >= nums[0]) l = 0;else{l = r+1;r = nums.length-1;}// 2.二次二分while(l<r){int mid = (l+r+1)/2;if(nums[mid] <= target){l = mid;}else{r = mid-1;}}return target == nums[r] ? r:-1;}public static void main(String[] args) {Scanner sc = new Scanner(System.in);System.out.println("输入旋转数组长度");int n = sc.nextInt();int[] nums = new int[n];for(int i = 0 ; i < n;i++){nums[i] = sc.nextInt();}System.out.println("输入目标值");int target = sc.nextInt();System.out.println("目标下标为"+findT(nums,target));}
}