日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

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

發布時間:2024/2/28 java 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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版)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。