leetcode 581. 最短无序连续子数组(详解普通 / 进阶 / 单调栈解法,Java版)
题目
题解
方法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版)相关推荐
- LeetCode 581. 最短无序连续子数组 (unfinished 排序+双指针)
581. 最短无序连续子数组 class Solution {public:int findUnsortedSubarray(vector<int>& nums) {vector& ...
- LeetCode 581. 最短无序连续子数组(排序单调栈)
文章目录 1. 题目 2. 解题 2.1 排序 2.2 4次遍历 2.3 单调栈 1. 题目 给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序. ...
- leetcode 581. Shortest Unsorted Continuous Subarray | 581. 最短无序连续子数组(单调栈)
题目 https://leetcode.com/problems/shortest-unsorted-continuous-subarray/ 题解 乍一看,没思路,直奔 Related Topics ...
- Leetcode 581.最短无序连续子数组
最短无序连续子数组 给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序. 你找到的子数组应是最短的,请输出它的长度. 示例 1: 输入: [2, ...
- LeetCode 581. 最短无序连续子数组(Shortest Unsorted Continuous Subarray)
581. 最短无序连续子数组 581. Shortest Unsorted Continuous Subarray 题目描述 给定一个整型数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序 ...
- 【LeetCode】【HOT】581. 最短无序连续子数组
[LeetCode][HOT]581. 最短无序连续子数组 文章目录 [LeetCode][HOT]581. 最短无序连续子数组 package hot;public class Solution58 ...
- 581. 最短无序连续子数组 golang
581. 最短无序连续子数组 给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序. 你找到的子数组应是最短的,请输出它的长度. 示例 1: 输入: ...
- LeetCode 862. 和至少为 K 的最短子数组(前缀和+deque单调栈)
1. 题目 返回 A 的最短的非空连续子数组的长度,该子数组的和至少为 K . 如果没有和至少为 K 的非空子数组,返回 -1 . 示例 1: 输入:A = [1], K = 1 输出:1示例 2: ...
- C#LeetCode刷题之#581-最短无序连续子数组( Shortest Unsorted Continuous Subarray)
问题 给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序. 你找到的子数组应是最短的,请输出它的长度. 输入: [2, 6, 4, 8, 10, ...
最新文章
- 奖学金pascal程序
- extractCSS – 帮助你从 HTML 中快速分离出 CSS
- 【英语学习】【WOTD】shard 释义/词源/示例
- C# WPF框架从http协议上获取返回的json数据及其解析json数据
- 基于udp的协议netty课设题目_Netty UDP示例
- GitHub 披露宕机原因;谷歌前 AI 研究员被解雇后成立独立研究所;常用 Linux 桌面版排行榜出炉 | 开源日报
- labelme安装及标签制作
- 计算机财务模型管理实验内容,计算机财务管理实验报告详细分解.doc
- Matlab与线性代数 -- Hilbert矩阵
- pandas对索引列index重新整理顺序
- 如何选择和设置SEO关键词
- 【python 目标检测】基于深度学习的道路破损检测|yolov5|VOC
- java编程思想学习笔记——21多线程
- UnsatisfiedDependencyException报错的原因
- ubuntu下高通平台模组串口驱动及使用
- Java删除Maven下的.lastUpdated文件
- IOS苹果手机下载DNF韩服手游手机版ios版下载
- 【Leetcode】天堂硅谷·数字经济算法编程大赛(虚拟)
- NO_ACCESS Protection
- 视频图像处理技术优势安防视频监控应用