壹 ❀ 引

早在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 题解分析的更多相关文章

  1. Java实现 LeetCode 154 寻找旋转排序数组中的最小值 II(二)

    154. 寻找旋转排序数组中的最小值 II 假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). 请找 ...

  2. [LeetCode] 154. 寻找旋转排序数组中的最小值 II

    题目链接 : https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array-ii/ 题目描述: 假设按照升序排序的数组在预 ...

  3. Leetcode之二分法专题-154. 寻找旋转排序数组中的最小值 II(Find Minimum in Rotated Sorted Array II)

    Leetcode之二分法专题-154. 寻找旋转排序数组中的最小值 II(Find Minimum in Rotated Sorted Array II) 假设按照升序排序的数组在预先未知的某个点上进 ...

  4. 154寻找旋转排序数组中的最小值II

    title: 寻找旋转排序数组中的最小值II 题目描述 题目链接:寻找旋转排序数组中的最小值II 解题思路 和上题同理:数组特点有 nums[mid] < nums[right],最小值肯定在m ...

  5. 领扣(LeetCode)寻找旋转排序数组中的最小值 个人题解

    假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). 请找出其中最小的元素. 你可以假设数组中不存在重 ...

  6. 154. 寻找旋转排序数组中的最小值 II

    转跳点:--\(˙<>˙)/-- 原本打算大年三十十一起写完的,结果这篇拖到了年初一…… 这道题比刚刚那道,麻烦一点,因为有重复,所以我们需要考虑重复的情况,就是刚刚的两种情况变成了三种: ...

  7. LeetCode154.寻找旋转排序数组中的最小值 II

    154.寻找旋转排序数组中的最小值 II 描述 假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). ...

  8. LeetCode:寻找旋转排序数组中的最小值【153】

    LeetCode:寻找旋转排序数组中的最小值[153] 题目描述 假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0 ...

  9. lintcode:寻找旋转排序数组中的最小值 II

    寻找旋转排序数组中的最小值 II 假设一个旋转排序的数组其起始位置是未知的(比如0 1 2 4 5 6 7 可能变成是4 5 6 7 0 1 2). 你需要找到其中最小的元素. 数组中可能存在重复的元 ...

  10. Java实现 LeetCode 153 寻找旋转排序数组中的最小值

    153. 寻找旋转排序数组中的最小值 假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). 请找出其中 ...

随机推荐

  1. jdk与tomcat的安装部署(CentOS8)(VM)

    一.登陆CentOS8 通过VMware Workstation登陆CentOS8系统   二.VMware Tools安装 1.找到VMware Tools对应文件: VMwareTools-10. ...

  2. 基于python+django的求职招聘网站-网上招聘管理系统设计与实现

    该系统是基于python+django的求职招聘网站.网上招聘管理系统.网上人才招聘系统.毕业生求职招聘系统.大学生求职招聘系统.校园招聘系统.企业招聘系统.系统适合场景:大学生.课程作业.毕业设计. ...

  3. SD Host控制器的系统集成

    控制器集成需求 SD Host可以从外部读取数据存储到SRAM和eFlash或者可以从内部读取数据输出到外部存储 AHB Bus slave接口用于配置 master接口作为主设备,DMA可以控制总线 ...

  4. SQL联结

    1联结 那我们又该如何创建联结呢? So easy! 规定要联结的所有表以及它们如何关联就可以了. 在设置关联条件时,为避免不同表被引用的列名相同,我们需要使用完全限定列名(用一个点分隔表名和列名), ...

  5. Java进程内线程数量限制的相关学习

    Java进程内线程数量限制的相关学习 背景 还是之前出现 cannot create native thread 的问题的后续 周末在家学习了下如何在容器外抓取dump. 也验证了下能否开启超过宿主机 ...

  6. [转帖]SQL SERVER DBCC命令详解

    https://developer.aliyun.com/article/867768   简介: SQL数据库开发 DBCC DROPCLEANBUFFERS:从缓冲池中删除所有缓存,清除缓冲区 在 ...

  7. [转帖]关于UNDO

    原文地址:https://www.modb.pro/db/70802?xzs= 一:请描述什么是Oracle Undo. 二:请描述UNDO的作用. 三:请谈谈你对Manual Undo Manage ...

  8. [转帖]使用Transformers推理

    https://github.com/ymcui/Chinese-LLaMA-Alpaca/wiki/%E4%BD%BF%E7%94%A8Transformers%E6%8E%A8%E7%90%86 ...

  9. .NET Core(C#) PadLeft和PadRight特定格式字符串长度补齐的方法和js中如何填充字符串

    .NET Core(C#) 1、PadLeft和PadRight使用说明 两个方法都是对字符串格式化进行补齐填充,PadLeft是左边,而PadRight是右边 '1010'.PadLeft(10,' ...

  10. Unity2019使用Android Studio 4出安卓包

    前言 在我所经历的项目组中有这几种方法来生成APK 直接在Unity生成APK,可以接入SDK 使用Unity导出Android Studio工程手动生成APK 使用Unity导出Android St ...