题目

题解

方法1(暴力排序):时间复杂度O(nlogn),空间复杂度O(n)

一个简单的想法是:将数组 nums 进行排序,记为 nums_sorted 。然后比较 nums 和 nums_sorted 的元素来决定最左边和最右边不匹配的元素。它们之间的子数组就是要求的最短无序子数组。

public int findUnsortedSubarray(int[] nums) {int[] snums = nums.clone();Arrays.sort(snums);int start = snums.length, end = 0;for (int i = 0; i < snums.length; i++) {if (snums[i] != nums[i]) {start = Math.min(start, i);end = Math.max(end, i);}}return (end - start >= 0 ? end - start + 1 : 0);
}

方法2(单调栈思想):时间复杂度O(n),空间复杂度O(n)

我们需要找到无序子数组中 最小元素最大元素 分别对应的 正确位置,来求得我们想要的无序子数组的边界。

为了达到这一目的,此方法中,我们使用 单调栈结构

我们从头遍历 nums 数组,如果遇到的数字大小一直是升序的,我们就不断把对应的下标压入栈中,这么做是因为这些元素在目前都是 处于正确的位置上。一旦我们遇到 前面的数比后面的数大,也就是 nums[j] 比栈顶元素小,我们可以知道 nums[j] 一定不在正确的位置上。为了找到 nums[j] 的正确位置,我们 不断将栈顶元素弹出,直到栈顶元素比 nums[j] 小,我们假设栈顶元素对应的下标为 k ,那么我们知道 nums[j] 的正确位置下标应该是 k+1

我们重复这一过程,直到遍历完整个数组,这样我们可以找到 最小的 k, 它就是 无序子数组的左边界

(实际上:所谓左边界,就是 “所有未在正确位置的数当中最小的那个” 的正确位置,在数值上等同于 “所有的左边界当中最小的左边界”。同样地,所谓右边界,就是 “所有未在正确位置的数当中最大的那个” 的正确位置,在数值上等同于 “所有的右边界当中最大的右边界”。)

类似地,我们逆序遍历一遍 nums 数组来找到无序子数组的 右边界。这一次我们将降序的元素压入栈中,如果遇到一个升序的元素,我们像上面所述的方法一样不断将栈顶元素弹出,直到找到一个更大的元素,以此找到无序子数组的右边界。

我们可以看下图作为参考。从图中可以观察到,上升还是下降决定了相对顺序;还可以观察到,指针 b 指向所有未在正确位置的数当中的最小的那个,它在下标 0 后面标记着 “无序子数组中最小的左边界” 1;指针 a 指向所有未在正确位置的数当中的最大的那个,它在下标 7 前面标记着 “无序子数组中最大的右边界” 6。

public static int findUnsortedSubarray(int[] nums) {Stack<Integer> stack = new Stack<Integer>(); // 单调栈int left = nums.length; // 左边界int right = 0; // 右边界for (int i = 0; i < nums.length; i++) { // 找到左边界while (!stack.isEmpty() && nums[stack.peek()] > nums[i])left = Math.min(left, stack.pop()); // 取所有的左边界当中最小的左边界stack.push(i);}stack.clear();for (int i = nums.length - 1; i >= 0; i--) { // 找到右边界while (!stack.isEmpty() && nums[stack.peek()] < nums[i])right = Math.max(right, stack.pop()); // 取所有的右边界当中最大的右边界stack.push(i);}return right - left > 0 ? right - left + 1 : 0;
}

方法3(进阶):时间复杂度O(n),空间复杂度O(1)

同时从前往后和从后往前遍历,分别得到要排序数组的右边界和左边界;

寻找右边界:

从前往后遍历的过程中,用 max 记录遍历过的最大值,如果 max 大于当前的 nums[i],说明nums[i] 的位置不正确,属于需要排序的数组,因此将右边界更新为 i,然后更新 max;这样最终可以找到需要排序的数组的右边界,右边界之后的元素都大于 max;

寻找左边界:

从后往前遍历的过程中,用 min 记录遍历过的最小值,如果 min 小于当前的 nums[j],说明 nums[j] 的位置不正确,应该属于需要排序的数组,因此将左边界更新为j,然后更新 min;这样最终可以找到需要排序的数组的左边界,左边界之前的元素都小于 min;

注:从前往后遍历和从后往前遍历两个过程可以分两次循环完成,也可以放一起完成,这样的话就有:j = len-i-1

public static int findUnsortedSubarray(int[] nums) {int len = nums.length;int max = nums[0]; // max记录遍历过的最大值int min = nums[len - 1]; // min记录遍历过的最小值int left = 0, right = -1; // 要排序数组的左边界、右边界for (int i = 0; i < len; i++) {// 从前往后遍历if (max > nums[i]) {right = i;} else {max = nums[i];}// 从后往前遍历if (min < nums[len - i - 1]) {left = len - i - 1;} else {min = nums[len - i - 1];}}return right - left + 1;
}

方法 3 执行用时:

leetcode 581. 最短无序连续子数组(详解普通 / 进阶 / 单调栈解法,Java版)相关推荐

  1. LeetCode 581. 最短无序连续子数组 (unfinished 排序+双指针)

    581. 最短无序连续子数组 class Solution {public:int findUnsortedSubarray(vector<int>& nums) {vector& ...

  2. LeetCode 581. 最短无序连续子数组(排序单调栈)

    文章目录 1. 题目 2. 解题 2.1 排序 2.2 4次遍历 2.3 单调栈 1. 题目 给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序. ...

  3. leetcode 581. Shortest Unsorted Continuous Subarray | 581. 最短无序连续子数组(单调栈)

    题目 https://leetcode.com/problems/shortest-unsorted-continuous-subarray/ 题解 乍一看,没思路,直奔 Related Topics ...

  4. Leetcode 581.最短无序连续子数组

    最短无序连续子数组 给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序. 你找到的子数组应是最短的,请输出它的长度. 示例 1: 输入: [2, ...

  5. LeetCode 581. 最短无序连续子数组(Shortest Unsorted Continuous Subarray)

    581. 最短无序连续子数组 581. Shortest Unsorted Continuous Subarray 题目描述 给定一个整型数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序 ...

  6. 【LeetCode】【HOT】581. 最短无序连续子数组

    [LeetCode][HOT]581. 最短无序连续子数组 文章目录 [LeetCode][HOT]581. 最短无序连续子数组 package hot;public class Solution58 ...

  7. 581. 最短无序连续子数组 golang

    581. 最短无序连续子数组 给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序. 你找到的子数组应是最短的,请输出它的长度. 示例 1: 输入: ...

  8. LeetCode 862. 和至少为 K 的最短子数组(前缀和+deque单调栈)

    1. 题目 返回 A 的最短的非空连续子数组的长度,该子数组的和至少为 K . 如果没有和至少为 K 的非空子数组,返回 -1 . 示例 1: 输入:A = [1], K = 1 输出:1示例 2: ...

  9. C#LeetCode刷题之#581-最短无序连续子数组( Shortest Unsorted Continuous Subarray)

    问题 给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序. 你找到的子数组应是最短的,请输出它的长度. 输入: [2, 6, 4, 8, 10, ...

最新文章

  1. 奖学金pascal程序
  2. extractCSS – 帮助你从 HTML 中快速分离出 CSS
  3. 【英语学习】【WOTD】shard 释义/词源/示例
  4. C# WPF框架从http协议上获取返回的json数据及其解析json数据
  5. 基于udp的协议netty课设题目_Netty UDP示例
  6. GitHub 披露宕机原因;谷歌前 AI 研究员被解雇后成立独立研究所;常用 Linux 桌面版排行榜出炉 | 开源日报
  7. labelme安装及标签制作
  8. 计算机财务模型管理实验内容,计算机财务管理实验报告详细分解.doc
  9. Matlab与线性代数 -- Hilbert矩阵
  10. pandas对索引列index重新整理顺序
  11. 如何选择和设置SEO关键词
  12. 【python 目标检测】基于深度学习的道路破损检测|yolov5|VOC
  13. java编程思想学习笔记——21多线程
  14. UnsatisfiedDependencyException报错的原因
  15. ubuntu下高通平台模组串口驱动及使用
  16. Java删除Maven下的.lastUpdated文件
  17. IOS苹果手机下载DNF韩服手游手机版ios版下载
  18. 【Leetcode】天堂硅谷·数字经济算法编程大赛(虚拟)
  19. NO_ACCESS Protection
  20. 视频图像处理技术优势安防视频监控应用

热门文章

  1. PAT (Basic Level) 1050 螺旋矩阵(模拟)
  2. HDU4082(相似三角形的个数)
  3. 对现有的所能找到的DDOS代码(攻击模块)做出一次分析----UDP篇
  4. DLL入门浅析(3)——从DLL中导出变量
  5. 数据结构与算法 | 斐波那契查找
  6. python中lxml模块的使用
  7. python中的线程threading.Thread()使用
  8. 看完这篇还不清楚Netty的内存管理,那我就哭了!
  9. 曹大带我学 Go(8)—— 一个打点引发的事故
  10. OS- -内存之虚拟内存