JS Leetcode 33. 搜索旋转排序数组题解,图解旋转数组中的二分法
壹 ❀ 引
本来今天(2021.4.7)的每日一题是81. 搜索旋转排序数组 II,但今天工作很忙,下班人基本累个半死,题目别说按照二分法的思路做不出来,连题解看了会都没法沉下心去看,不过得到的信息是,本题属于另一道的变体,而且若先了解另一题,对于本题会有较大的帮助,想了想就还是先记录之前的题,题目来自LeetCode33. 搜索旋转排序数组,题目难度同样是中等,题目描述如下:
整数数组 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
今天就熬个夜先记录和理解本题吧,明天再把升级版的题目再补回来。
贰 ❀ 简单分析与二分法
JS的同学可能看到此题,本能想到的就是findIndex了,不过要是用这种来解题,本身就没什么意义了,所以这种投机取巧的做法就不说了,对于算法也没太大提升,我们直接介绍二分法做法。
我在JS leetcode 寻找旋转排序数组中的最小值 题解分析,你不得不了解的二分法一文中,有简单提及二分法,而且比较巧的是,这道题也是旋转数组。关于二分法查找的优点是,每次条件判断后总能舍弃掉一半的元素,从而大大加快查找的效率,二分法的时间复杂度是O(logn),我们先上一个查找目标元素的二分法模板:
// 查找目标值二分法模板
function binarySearch(arr, target) {
var low = 0;
var high = arr.length - 1;
while (low <= high) {
var mid = Math.floor((low + high) / 2);
if (target === arr[mid]) {
return mid;
} else if (target > arr[mid]) {
low = mid + 1;
} else {
high = mid - 1;
};
};
return -1;
};
而对于本题来说,较为难受的是数组虽然是有序数组,但是一个经过旋转的有序数组,我们不知道在哪个点进行了旋转,所以一般的二分法在这行不通。
对于常规二分法,我们是根据目标值与mid对比,从而确定目标值在mid的左侧或者右侧(或者运气好直接相等找到了),从而不断缩小范围。但事实上,对于旋转的有序数组依旧有规律可循。
我们以数组[1,2,3,4,5]为例,我们要找到3,它可能存在旋转情况如下:

如上图,第一行为为旋转,下面四行为此数组可能旋转的所有情况,我们找出mid,根据与nums[0]的大小对比,可以得知:
- 若mid<nums[0],那么mid在右侧有序序列,比如
[2,3,4] - 若mid>=nums[0],那么mid在左侧有序序列,比如
[3,4,5],注意,为什么是>=后面会解释。
这样我们就已经对于区域做了一次划分,但既然是二分法,自然得舍弃掉一半的元素,此时就得依赖target了,判断依据其实很简单。
假设我们的数组是[5,1,2,3,4]找3,我们先得知有序序列在右侧,也就是[2,3,4],我们将这个范围理解为[mid,end],那么只要target>mid&&target<=end,那就说明3一定在右侧有序序列中,左边的[5,1]可以直接舍弃。
接下来我们可以调整左侧边界为mid+1继续搜索,为什么加1呢?因为如果mid===target已经返回了,能走到这一步自然mid不会相等,下次调整边界自然可以舍弃掉,用图表示这个过程如下:

有同学可能就想到,你这样解释太过于理想了,如果target在无序那边呢?其实也不冲突,我们还是假设[5,1,2,3,4]中找1。
很明显由于mid<5,所以有序部分在右侧,但因为target并不满足target>mid&&target<=end,因此右边界调整为mid-1,于是我们舍弃了右边部分,得到了[5,1]。
接下来怎么办?当然还是重复判断哪边为有序部分,哪边不是,我们同样还是找到mid,也就是5,由于此时mid>=nums[0],也就是5>=5,因此mid在左侧有序部分,所以得到了有序部分[5]以及无序部分[1],哎,到这里你是不是知道了为什么是>=了?找出有序部分的目的,其实就是为了方便我们利用target>mid && target<=end(假设有序有右侧)来决定放弃哪一部分,如果你的数组不是有序的,target>mid&&target<=end这个公式你根本没法满足。
那么上面这个过程用图就是下面这样:

解释的够清楚了,直接上代码:
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var search = function (nums, target) {
let l = 0;
let r = nums.length - 1;
while (l <= r) {
const mid = Math.floor((l + r) / 2);
if (nums[mid] === target) {
return mid;
};
if (nums[mid] >= nums[l]) {
//target 在 [l, mid] 之间
if (target >= nums[l] && target < nums[mid]) {
r = mid - 1;
} else {
//target 不在 [l, mid] 之间
l = mid + 1;
};
} else {
// [mid, r]有序
// target 在 [mid, r] 之间
if (target > nums[mid] && target <= nums[r]) {
l = mid + 1;
} else {
// target 不在 [mid, r] 之间
r = mid - 1;
}
}
}
return -1;
};
总结下解题的核心,第一点,根据mid与nums[0](第一位是可变的,所以其实是nums[左边界])决定哪一边是有序序列,对有序序列套用target>mid && target<=r从而得知target在不在有序序列这一边,不在自然在无序那一边,继续循环上述步骤,找到最终答案。
真的累了,2点了....睡觉。这题就说到这里了。
嗯....图片貌似有点大,确实困了...就这样吧。
JS Leetcode 33. 搜索旋转排序数组题解,图解旋转数组中的二分法的更多相关文章
- Java实现 LeetCode 33 搜索旋转排序数组
33. 搜索旋转排序数组 假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). 搜索一个给定的目标值, ...
- 力扣Leetcode 33. 搜索旋转排序数组
33. 搜索旋转排序数组 假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). 搜索一个给定的目标值, ...
- [LeetCode]33. 搜索旋转排序数组(二分)
题目 假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). 搜索一个给定的目标值,如果数组中存在这个目 ...
- [leetcode] 33. 搜索旋转排序数组(Java)
33. 搜索旋转排序数组 说实话这题我连题都没有看懂....真是醉了 二分,没意思,直接交了- - https://www.jiuzhang.com/solutions/search-in-rotat ...
- leetcode 33. 搜索旋转排序数组 及 81. 搜索旋转排序数组 II
33. 搜索旋转排序数组 问题描述 假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). 搜索一个给定 ...
- LeetCode 33 - 搜索旋转排序数组 - [二分]
假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). 搜索一个给定的目标值,如果数组中存在这个目标值, ...
- LeetCode 33 搜索旋转排序数组
题目: 假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). 搜索一个给定的目标值,如果数组中存在这个 ...
- [LeetCode] 33. Search in Rotated Sorted Array 在旋转有序数组中搜索
Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. (i.e. ...
- LeetCode 33——搜索旋转排序数组
1. 题目 2. 解答 2.1. 方法一 直接进行二分查找,在判断查找方向的时候详细分类. 当 nums[mid] < target 时, 若 nums[left] <= nums[mid ...
- leetcode 33搜索旋转排序数组
暴力解法:O(n) 想办法用二分查找Ologn
随机推荐
- springboot启动流程 (2) 组件扫描
SpringBoot的组件扫描是基于Spring @ComponentScan注解实现的,该注解使用basePackages和basePackageClasses配置扫描的包,如果未配置这两个参数,S ...
- Python Code_05位运算
coding:utf-8 author : 写bug的盼盼 development time : 2021/8/28 7:16 print(4&8)#非1即0 print(4|2)#同0即0, ...
- Linux复习笔记
Linux复习笔记 常识说明 目录结构 Linux以树型结构管理文件,其最上层文件夹为 / ,也就是根目录. 如图所示,图中展示了一部分文件夹的结构: 所有的文件夹都属于根目录的子文件夹. 安装好系统 ...
- 单元测试中如何Mock HttpContext
最近团队有小伙伴问在单元测试中如何Mock HttpContext. 这是一个好问题,整理了一个实现方案分享给大家. 在C#中,尤其是在单元测试场景下,模拟(Mocking)HttpContext 是 ...
- [转帖]Linux 下rsync命令详细整理
https://blog.csdn.net/weixin_44052462/article/details/116134761 rsync是一个功能非常强大的工具,其命令也有很多功能特色选项,我们下面 ...
- [转帖]深度硬核文:Nginx的301重定向处理过程分析
https://zhuanlan.zhihu.com/p/84539204 本文首发于公众号:js-mindmap 一,序言 "晚上九点,办公室里烟雾缭绕,工作进度依然没有什么进展.王二胖打 ...
- [转帖]061、监控指标之TiKV
资源相关 Grafana监控 TiKV-Details -> Cluster - Store Size / Available Size Grafana监控 TiKV-Details -> ...
- [转帖]Jmeter性能测试:高并发分布式性能测试
一.为什么要进行分布式性能测试 当进行高并发性能测试的时候,受限于Jmeter工具本身和电脑硬件的原因,无法满足我们对大并发性能测试的要求.基于这种场景下,我们就需要采用分布式的方式来实现我们高并发的 ...
- 【小测试】rust中的无符号整数溢出
作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 1.在编译阶段就可以识别出来的溢出 fn main(){ ...
- 【JS 逆向百例】当乐网登录接口参数逆向
声明 本文章中所有内容仅供学习交流,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除! 逆向目标 目标:当乐网登录 主页:https://oauth.d.cn ...