JS Leetcode 154. 寻找旋转排序数组中的最小值 II 题解分析
壹 ❀ 引
早在10个月前,也就是去年,我记录了JS leetcode 寻找旋转排序数组中的最小值 题解分析,你不得不了解的二分法一题,那么这篇文章记录它的升级版,来自LeetCode154. 寻找旋转排序数组中的最小值 II,但是我现在回头看之前这篇文章,解题思路更像是找规律,有点难以记忆。我在前几天记录的另外两篇旋转数组中使用了相同的解题思路,所以为了思路上的统一,我想用相同的思路先把153. 寻找旋转排序数组中的最小值先重新梳理一遍,再来看它的升级版。回归正题,154. 寻找旋转排序数组中的最小值 II题目描述如下:
已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,4,4,5,6,7] 在变化后可能得到:
若旋转 4 次,则可以得到 [4,5,6,7,0,1,4]
若旋转 7 次,则可以得到 [0,1,4,4,5,6,7]
注意,数组 [a[0], a[1], a[2], ..., a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], ..., a[n-2]] 。给你一个可能存在 重复 元素值的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。
示例 1:
输入:nums = [1,3,5]
输出:1
示例 2:
输入:nums = [2,2,2,0,1]
输出:0
提示:
n == nums.length
1 <= n <= 5000
-5000 <= nums[i] <= 5000
nums 原来是一个升序排序的数组,并进行了 1 至 n 次旋转进阶:
这道题是 寻找旋转排序数组中的最小值 的延伸题目。
允许重复会影响算法的时间复杂度吗?会如何影响,为什么?
贰 ❀ 思路分析与二分法
OK,我们还是先重新复习下153. 寻找旋转排序数组中的最小值这题,此题与升级版的题目唯一区别是数组中不存在重复项,即是一个数字不重复的被旋转的升序数组,让你找到数组中的最小值。
因为前面我们已经做了两题关于旋转数组的题目,已经总结出了一种二分法的思路,这里直接再次套用这种解题思路,比如要找到[4,5,0,1,2,3]中的最小值,我们依然可以用mid与nums[0]进行比较,如果mid>=nums[0]说明升序部分在左侧,如果mid<nums[0]说明升序部分在右侧,我们用图画出来,感受下这个规律:
图1

如上图,通过中间数mid与nums[0]的大小比较就能知道升序在哪一边。如果升序在这一边,那么最小值一定在不是升序的这一边,看图自己感受下。当然有个特例,数组没旋转的情况下,也满足mid>=nums[0],但最小值其实在左侧,没关系,因为只有未旋转的数组nums[0]<=nums[length-1],比如:
let arr = [1];
arr[0]<=arr[arr.length-1]; //true
let arr = [1,2]
arr[0]<=arr[arr.length-1]; //true
让我们来实现这段代码:
var findMin = function (nums) {
let n = nums.length;
let l = 0;
let r = n - 1;
// 数组未旋转或者数组只有一位的情况
if (nums[l] <= nums[r]) {
return [nums[l]];
};
// 能走到这,说明数组一定旋转了
while (l < r) {
let mid = Math.floor((l + r) / 2);
// 如果mid>=nums[0],升序在左侧,最小在右侧,修改l的指针
if (nums[mid] >= nums[0]) {
// 为什么要加1,请看图感受
l = mid+1;
} else {
//反之升序在右侧,最小值在左侧,修改r指针
r = mid;
}
}
return nums[l] <= nums[r] ? nums[l] : nums[r];
};
我们来解释下这段代码中的几个注意点,第一个问题,为什么是nums[mid] >= nums[0],因为我们取mid是向下取整,比如数组[2,1],mid取的其实是nums[0]也就是2,因为nums[mid]其实等于nums[0],其实就是为了兼容这种情况。
第二个问题,为什么l=mid+1,而r不是mid-1呢?其实看我们上面列举的旋转的数组图示,你会发现当mid>=nums[0]时,由于升序在左侧,最小值在右侧,而且最小一定不可能是mid,所以直接mid+1,不然假设数组是[2,1]的情况,你会发现由于l=mid会一直等于0,然后陷入死循环。
而l不是mid-1看图其实也很清楚,因为有可能mid就是最小值,所以我们不能舍弃掉,这也算是画图找规律的一种,但整体思路其实还是与之前两道题相同。
OK,那么到这里我们用之前mid与nums[0]比较的思路,重新把这道题解了下,算是把思路给统一了,不然一道题一个思路也确实难以记忆。
那么回到它的升级版,也就是存在重复数的情况,我们甚至可以暴力点,直接数组去重后套用上面的代码,比如:
/**
* @param {number[]} nums
* @return {number}
*/
var findMin = function (nums) {
// 去重
nums = [...new Set(nums)]
// 下面不变
let n = nums.length;
let l = 0;
let r = n - 1;
// 数组未旋转或者数组只有一位的情况
if (nums[l] <= nums[r]) {
return [nums[l]];
};
// 能走到这,说明数组一定旋转了
while (l < r) {
let mid = Math.floor((l + r) / 2);
// 如果mid>=nums[0],升序在左侧,最小在右侧,修改l的指针
if (nums[mid] >= nums[0]) {
// 为什么要加1,请看图感受
l = mid+1;
} else {
//反之升序在右侧,最小值在左侧,修改r指针
r = mid;
}
}
return nums[l] <= nums[r] ? nums[l] : nums[r];
};
当然既然题目都给了重复数字,咱们直接去重多少差点意思,如果不去重我们如何解决这道题呢?
举个例子,假设数组为[3,1,3],上面的代码会直接挂掉,因为一开始就满足了nums[l] <= nums[r],其实在JS Leetcode 81. 搜索旋转排序数组 II 题解,补救二分法的可行性中,我们就解释了重复元素导致二分法特性丢失的问题,而挽救这种特性的办法就是,当数组的nums[l]===nums[r]时,我让任意一方的指针进行缩进,比如r++即可,因为给无数个3和给一个3,并不会影响到最终的结果判断。
所以我们修改下上方的代码,不用去重就是这样:
var findMin = function (nums) {
let n = nums.length;
let l = 0;
let r = n - 1;
while (l < r) {
// 只要左右指针相同,就让r--,比如[3,1,3]就会变成[3,1]
if (nums[l] <= nums[r]) {
return [nums[l]];
};
// 这个移进来了,如果放外面可能有[3,1,3]这种,同时也用于解决1个元素的情况以及未旋转的情况
if (nums[l] === nums[r]) {
r--;
break;
};
let mid = Math.floor((l + r) / 2);
// 如果mid>=nums[0],升序在左侧,最小在右侧,修改l的指针
if (nums[mid] >= nums[0]) {
// 为什么要加1,请看图感受
l = mid + 1;
} else {
//反之升序在右侧,最小值在左侧,修改r指针
r = mid;
}
}
return nums[l] <= nums[r] ? nums[l] : nums[r];
};
那么本文就到这里了,相关系列题型可见下方。
JS leetcode 153. 寻找旋转排序数组中的最小值 题解分析,你不得不了解的二分法
JS Leetcode 33. 搜索旋转排序数组题解,图解旋转数组中的二分法
JS Leetcode 81. 搜索旋转排序数组 II 题解,补救二分法的可行性
JS Leetcode 154. 寻找旋转排序数组中的最小值 II 题解分析的更多相关文章
- Java实现 LeetCode 154 寻找旋转排序数组中的最小值 II(二)
154. 寻找旋转排序数组中的最小值 II 假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). 请找 ...
- [LeetCode] 154. 寻找旋转排序数组中的最小值 II
题目链接 : https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array-ii/ 题目描述: 假设按照升序排序的数组在预 ...
- Leetcode之二分法专题-154. 寻找旋转排序数组中的最小值 II(Find Minimum in Rotated Sorted Array II)
Leetcode之二分法专题-154. 寻找旋转排序数组中的最小值 II(Find Minimum in Rotated Sorted Array II) 假设按照升序排序的数组在预先未知的某个点上进 ...
- 154寻找旋转排序数组中的最小值II
title: 寻找旋转排序数组中的最小值II 题目描述 题目链接:寻找旋转排序数组中的最小值II 解题思路 和上题同理:数组特点有 nums[mid] < nums[right],最小值肯定在m ...
- 领扣(LeetCode)寻找旋转排序数组中的最小值 个人题解
假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). 请找出其中最小的元素. 你可以假设数组中不存在重 ...
- 154. 寻找旋转排序数组中的最小值 II
转跳点:--\(˙<>˙)/-- 原本打算大年三十十一起写完的,结果这篇拖到了年初一…… 这道题比刚刚那道,麻烦一点,因为有重复,所以我们需要考虑重复的情况,就是刚刚的两种情况变成了三种: ...
- LeetCode154.寻找旋转排序数组中的最小值 II
154.寻找旋转排序数组中的最小值 II 描述 假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). ...
- LeetCode:寻找旋转排序数组中的最小值【153】
LeetCode:寻找旋转排序数组中的最小值[153] 题目描述 假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0 ...
- lintcode:寻找旋转排序数组中的最小值 II
寻找旋转排序数组中的最小值 II 假设一个旋转排序的数组其起始位置是未知的(比如0 1 2 4 5 6 7 可能变成是4 5 6 7 0 1 2). 你需要找到其中最小的元素. 数组中可能存在重复的元 ...
- Java实现 LeetCode 153 寻找旋转排序数组中的最小值
153. 寻找旋转排序数组中的最小值 假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). 请找出其中 ...
随机推荐
- jdk与tomcat的安装部署(CentOS8)(VM)
一.登陆CentOS8 通过VMware Workstation登陆CentOS8系统 二.VMware Tools安装 1.找到VMware Tools对应文件: VMwareTools-10. ...
- 基于python+django的求职招聘网站-网上招聘管理系统设计与实现
该系统是基于python+django的求职招聘网站.网上招聘管理系统.网上人才招聘系统.毕业生求职招聘系统.大学生求职招聘系统.校园招聘系统.企业招聘系统.系统适合场景:大学生.课程作业.毕业设计. ...
- SD Host控制器的系统集成
控制器集成需求 SD Host可以从外部读取数据存储到SRAM和eFlash或者可以从内部读取数据输出到外部存储 AHB Bus slave接口用于配置 master接口作为主设备,DMA可以控制总线 ...
- SQL联结
1联结 那我们又该如何创建联结呢? So easy! 规定要联结的所有表以及它们如何关联就可以了. 在设置关联条件时,为避免不同表被引用的列名相同,我们需要使用完全限定列名(用一个点分隔表名和列名), ...
- Java进程内线程数量限制的相关学习
Java进程内线程数量限制的相关学习 背景 还是之前出现 cannot create native thread 的问题的后续 周末在家学习了下如何在容器外抓取dump. 也验证了下能否开启超过宿主机 ...
- [转帖]SQL SERVER DBCC命令详解
https://developer.aliyun.com/article/867768 简介: SQL数据库开发 DBCC DROPCLEANBUFFERS:从缓冲池中删除所有缓存,清除缓冲区 在 ...
- [转帖]关于UNDO
原文地址:https://www.modb.pro/db/70802?xzs= 一:请描述什么是Oracle Undo. 二:请描述UNDO的作用. 三:请谈谈你对Manual Undo Manage ...
- [转帖]使用Transformers推理
https://github.com/ymcui/Chinese-LLaMA-Alpaca/wiki/%E4%BD%BF%E7%94%A8Transformers%E6%8E%A8%E7%90%86 ...
- .NET Core(C#) PadLeft和PadRight特定格式字符串长度补齐的方法和js中如何填充字符串
.NET Core(C#) 1、PadLeft和PadRight使用说明 两个方法都是对字符串格式化进行补齐填充,PadLeft是左边,而PadRight是右边 '1010'.PadLeft(10,' ...
- Unity2019使用Android Studio 4出安卓包
前言 在我所经历的项目组中有这几种方法来生成APK 直接在Unity生成APK,可以接入SDK 使用Unity导出Android Studio工程手动生成APK 使用Unity导出Android St ...