搜索旋转排序数组
- Ⅰ、搜索旋转排序数组:
- 1、题目描述:
- 2、解题思路:
- 3、实现代码:
- Ⅱ、小结:
Ⅰ、搜索旋转排序数组:
1、题目描述:
给你⼀个升序排列的整数数组 nums ,和⼀个整数 target 。
假设按照升序排序的数组在预先未知的某个点上进⾏了旋转。(例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
请你在数组中搜索 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
2、解题思路:
题⽬要求时间复杂度为 logn,因此基本就是⼆分法了。 这道题⽬不是直接的有序数组,不然就是 easy 了。
⾸先要知道,我们随便选择⼀个点,将数组分为前后两部分,其中⼀部分⼀定是有序的。
具体步骤:
我们可以先找出 mid,然后根据 nums[mid] 来判断,mid 是在有序的部分还是⽆序的部分;
假如 nums[mid] ⼩于 nums[start],则mid ⼀定在右边有序部分。
假如 nums[mid] ⼤于等于 nums[start], 则 mid ⼀定在左边有序部分。
注意等号的考虑 然后我们继续判断 target 在哪⼀部分, 我们就可以舍弃另⼀部分了;
我们只需要⽐较 target 和有序部分的边界关系就⾏了。
⽐如:mid 在右侧有序部分,即 [mid, end] 那么我们只需要判断 target >= nums[mid] && target <= nums[end] 就能知道 target 在右侧有序部分,我们就可以舍弃左边部分了(start = mid + 1), 反之亦然。
可能存在的问题:
其一、为什么 nums[mid] 小于 nums[start],则右边一定有序,而 nums[mid] ⼤于等于 nums[start],则
左边一定有序?
答:因为整数数组 nums 是升序排列的,且在未知的某个点上进⾏了旋转,那么其 nums[end] < nums[start]
是一定成立的;因此若 nums[mid] >= nums[start],就说明 nums[start] 到 nums[mid-1] 是升序的,因
此就可以说左边是有序部分;同理,若 nums[mid] < nums[start],就说明 nums[mid+1] 到 nums[end] 是
升序的;
3、实现代码:
其一、代码为:
const searchPermutation = (nums, target) => {
// 时间复杂度:O(logn)
// 空间复杂度:O(1)
let start = 0
let end = nums.length - 1
while (start <= end) {
// 此时的 ((end - start) >> 1) 操作是除法操作,但是会向下取整;
const mid = start + ((end - start) >> 1)
// 若 nums[mid] === target,则直接将 mid 值返回(即:目标值);
if (nums[mid] === target) return mid
if (nums[mid] >= nums[start]) {
// ⚠ 注意这⾥的等号;
// 若 nums[mid] >= nums[start] 成立,就表示 [start, mid] 有序;
if (target >= nums[start] && target <= nums[mid]) {
// 表示:target 在 [start, mid] 之间;
// 其实 target 不可能等于 nums[mid], 但是为了对称,还是加上了等号;
end = mid - 1
} else {
// 表示:target 不在 [start, mid] 之间;
start = mid + 1
}
} else {
// 若 nums[mid] >= nums[start] 不成立,就表示 [mid, end] 有序;
if (target >= nums[mid] && target <= nums[end]) {
// 表示:target 在 [mid, end] 之间;
start = mid + 1
} else {
// 表示:target 不在 [mid, end] 之间;
end = mid - 1
}
}
}
// 若 while(start <= end){} 没有返回值,就说明:数组中不存在这个 target(即:⽬标值);
return -1
}
// 此时的返回值为:7;
searchPermutation([6, 7, 8, 1, 2, 3, 4, 5], 5)
// 此时的返回值为:-1;
searchPermutation([13, 14, 17, 18, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], 16)
```//代码的执行过程如下所示:
执行 searchPermutation([6, 7, 8, 1, 2, 3, 4, 5], 5) 函数后代码执行的过程:
第一次循环:start 为 0,end 为 7,target 为 5,nums 着眼于 nums[0] 到 nums[7];
start end mid target nums[mid] nums[start]
0 <= 7 3 5 !== nums[3]=1 < nums[0]=6
start end mid nums[mid] target nums[end]
0 7 3 nums[3]=1 <= 5 <= nums[7]=5
start
3+1=4
第二次循环:start 为 4,end 为 7,target 为 5,nums 着眼于 nums[4] 到 nums[7];
start end mid target nums[mid] nums[start]
4 <= 7 5 5 !== nums[5]=3 >= nums[4]=2
start end mid nums[start] target nums[mid]
4 7 5 nums[4]=2 <= 5 > nums[5]=3
start
5+1=6
第三次次循环:start 为 6,end 为 7,target 为 5,nums 着眼于 nums[6] 到 nums[7];
start end mid target nums[mid] nums[start]
6 <= 7 6 5 !== nums[6]=4 >= nums[6]=4
start end mid nums[start] target nums[mid]
6 7 6 nums[6]=4 <= 5 > nums[6]=4
start
6+1=7
第四次次循环:start 为 7,end 为 7,target 为 5,nums 着眼于 nums[7] 到 nums[7];
start end mid target nums[mid]
7 <= 7 7 5 === nums[7]=5
return 7(即:返回 mid 值,此时函数的最终输出结果就是 7);
执行 searchPermutation([13, 14, 17, 18, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], 16) 函数后代码执行的过程:
第一次循环:start 为 0,end 为 15,target 为 16,nums 着眼于 nums[0] 到 nums[15];
start end mid target nums[mid] nums[start]
0 <= 15 7 16 !== nums[7]=4 < nums[0]=13
start end mid nums[mid] target nums[end]
0 15 7 nums[7]=4 <= 16 > nums[15]=12
end
7-1=6
第二次循环:start 为 0,end 为 6,target 为 16,nums 着眼于 nums[0] 到 nums[6];
start end mid target nums[mid] nums[start]
0 <= 6 3 16 !== nums[3]=18 >= nums[0]=13
start end mid nums[start] target nums[mid]
0 6 3 nums[0]=13 <= 16 <= nums[3]=18
end
3-1=2
第三次循环:start 为 0,end 为 2,target 为 16,nums 着眼于 nums[0] 到 nums[2];
start end mid target nums[mid] nums[start]
0 <= 2 1 16 !== nums[1]=14 >= nums[0]=13
start end mid nums[start] target nums[mid]
0 2 1 nums[0]=13 <= 16 <= nums[1]=18
end
1-1=0
第四次次循环:start 为 0,end 为 0,target 为 16,nums 着眼于 nums[0] 到 nums[0];
start end mid target nums[mid] nums[start]
0 <= 0 0 16 !== nums[0]=13 >= nums[0]=13
start end mid nums[start] target nums[mid]
0 0 0 nums[0]=13 <= 16 > nums[0]=13
start
0+1=1
第五次次循环:start 为 1,end 为 0,target 为 16,nums 着眼于 nums[1] 到 nums[0];
start end
1 > 0
return -1(即:返回 -1 的值,此时函数的最终输出结果就是 -1,说明:数组中不存在 16 (即:⽬标值,target));
其二、截图为:
// 调用的函数为:searchPermutation([6, 7, 8, 1, 2, 3, 4, 5], 5),此时的返回值为:7;
// 调用的函数为:searchPermutation([13, 14, 17, 18, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], 16),此时的返回值为:-1;
Ⅱ、小结:
其一、哪里有不对或不合适的地方,还请大佬们多多指点和交流!
其二、若有转发或引用本文章内容,请注明本博客地址(直接点击下面 url 跳转
) https://blog.csdn.net/weixin_43405300,创作不易,且行且珍惜!
其三、有兴趣的话,可以多多关注这个专栏(Vue(Vue2+Vue3)面试必备专栏)(直接点击下面 url 跳转
):https://blog.csdn.net/weixin_43405300/category_11525646.html?spm=1001.2014.3001.5482