🚩传送门:力扣题目

题目

给你一个整数数组 [LC]581. 最短无序连续子数组 - 图1 ,你需要找出一个 连续子数组 ,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。
请你找出符合题意的 最短 子数组,并输出它的长度。

示例 1:

输入:nums = [2,6,4,8,10,9,15] 输出:5 解释:你只需要对 [6, 4, 8, 10, 9] 进行升序排序,那么整个表都会变为升序排序。

解题思路:排序

我们可以假设把这个数组分成三段,左段和右段是标准的升序数组,中段数组虽是无序的,但满足最小值大于左段的最大值,最大值小于右段的最小值。
[LC]581. 最短无序连续子数组 - 图2

复杂度分析

时间复杂度:[LC]581. 最短无序连续子数组 - 图3,其中 [LC]581. 最短无序连续子数组 - 图4 是给定数组的长度,我们需要排序该数组一次。

空间复杂度:[LC]581. 最短无序连续子数组 - 图5,其中 [LC]581. 最短无序连续子数组 - 图6 是给定数组的长度,我们拷贝该数组一次。

官方代码

  1. class Solution {
  2. public static int findUnsortedSubarray(int[] nums) {
  3. int[] sorted = Arrays.copyOfRange(nums, 0, nums.length); // 拷贝新数组
  4. Arrays.sort(sorted); // 新数组排序
  5. int i = 0, end = nums.length - 1;
  6. // 左段有序的,所以从左向右第一个不一致的下标就是中段的左边界begin
  7. while (begin < nums.length && sorted[begin] == nums[begin]) begin++;
  8. while (end >= 0 && sorted[end] == nums[end]) end--; // 右段有序的,所以从右向左第一个不一致的下标就是中段的右边界end
  9. return end <= begin ? 0 : end - begin + 1; // 中段如果存在,begin必然小于end
  10. }
  11. }

解题思路:一次遍历

我们可以假设把这个数组分成三段,左段和右段是标准的升序数组,中段数组虽是无序的,但满足最小值大于左段的最大值,最大值小于右段的最小值。
image.png
那么我们目标就很明确了,找中段的左右边界,我们分别定义为[LC]581. 最短无序连续子数组 - 图8[LC]581. 最短无序连续子数组 - 图9;
分两头开始遍历:

  • 从左到右维护一个最大值[LC]581. 最短无序连续子数组 - 图10,在进入右段之前,遍历到的[LC]581. 最短无序连续子数组 - 图11都是小于[LC]581. 最短无序连续子数组 - 图12的,我们要求的[LC]581. 最短无序连续子数组 - 图13是遍历中最后一个小于[LC]581. 最短无序连续子数组 - 图14元素的位置;
  • 从右到左维护一个最小值[LC]581. 最短无序连续子数组 - 图15 ,在进入左段之前,遍历到的[LC]581. 最短无序连续子数组 - 图16都是大于[LC]581. 最短无序连续子数组 - 图17 的,我们要求的[LC]581. 最短无序连续子数组 - 图18是遍历中最后一个大于[LC]581. 最短无序连续子数组 - 图19 元素的位置。

复杂度分析

时间复杂度:[LC]581. 最短无序连续子数组 - 图20,其中 [LC]581. 最短无序连续子数组 - 图21 是给定数组的长度,我们仅需要遍历该数组一次。

空间复杂度:[LC]581. 最短无序连续子数组 - 图22,我们只需要常数的空间保存若干变量。

官方代码

  1. class Solution {
  2. public int findUnsortedSubarray(int[] nums) {
  3. // 初始化
  4. int len = nums.length;
  5. int min = nums[len-1];
  6. int max = nums[0];
  7. int begin = 0, end = -1;
  8. // 遍历
  9. for(int i = 0; i < len; i++){
  10. if(nums[i] < max){
  11. end = i; // 从左到右维持最大值,寻找右边界 end
  12. }else{
  13. max = nums[i];
  14. }
  15. if(nums[len-i-1] > min){
  16. begin = len-i-1; // 从右到左维持最小值,寻找左边界 begin
  17. }else{
  18. min = nums[len-i-1];
  19. }
  20. }
  21. return end-begin+1;
  22. }
  23. }