LeetCode 581. 最短无序连续子数组

581. 最短无序连续子数组

题目描述

给你一个整数数组 nums ,你需要找出一个 连续子数组 ,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。

请你找出符合题意的 最短 子数组,并输出它的长度.

示例 1:

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

示例 2:

输入:nums = [1,2,3,4]
输出:0

示例 3:

输入:nums = [1]
输出:0

解题思路

思路一: 遍历

可以假设把这个数组分成三段,左段和右段是标准的升序数组,中段数组虽是无序的,但满足最小值大于左段的最大值,最大值小于右段的最小值
定义中段的左右边界,我们分别定义为left 和 right;
分两头开始遍历:

  • 从左到右维护一个最大值max,在进入右段之前,那么遍历到的nums[i]都是小于max的,我们要求的right就是遍历中最后一个小于max元素的位置;
  • 同理,从右到左维护一个最小值min,在进入左段之前,那么遍历到的nums[i]也都是大于min的,要求的left也就是最后一个大于min元素的位置

注意,当原数组有序时, 直接返回0.

实现代码如下:

/**
 * @param {number[]} nums
 * @return {number}
 */
var findUnsortedSubarray = function(nums) {
    // 先判断是否有序
    if (isSorted(nums)) {
        return 0;
    }
    //初始化
    let len = nums.length,  
        min = nums[len - 1],
        max = nums[0],
        left = 0, 
        right = -1;
    // 遍历
    for(let i = 0; i < len; i++){
        if (nums[i] < max){      //从左到右维持最大值,寻找右边界right
            right = i;
        } else{
            max = nums[i];
        }
        
        if(nums[len - i - 1] > min){    //从右到左维持最小值,寻找左边界left
            left = len - i - 1;
        } else{
            min = nums[len - i - 1];
        }            
    }
    return right - left + 1;
};

const isSorted = (nums) => {
    for (let i = 1; i < nums.length; i++) {
        if (nums[i] < nums[i - 1]) {
            return false;
        }
    }
    return true;
}  
  • 时间复杂度:O(n),其中 n 为给定数组的长度。

  • 空间复杂度:O(1)

思路二: 双指针 + 排序

可以先将数组拷贝一份进行排序,然后使用两个指针 left 和 right 分别找到左右两端第一个不同的地方,那么 [left, right] 这一区间即是答案
实现代码如下:

/**
 * @param {number[]} nums
 * @return {number}
 */
var findUnsortedSubarray = function(nums) {
    if (nums.length == 1 || isSorted(nums)) {
        return 0;
    }    
    let numsSorted = [...nums].sort((a, b) => a - b), 
        len = nums.length;
    let left = 0, right = len - 1;
    while (left <= right && nums[left] == numsSorted[left]) left++;
    while (left <= right && nums[right] == numsSorted[right]) right--;
    return right - left + 1;
};

const isSorted = (nums) => {
    for (let i = 1; i < nums.length; i++) {
        if (nums[i] < nums[i - 1]) {
            return false;
        }
    }
    return true;
}  
  • 时间复杂度: O(nlogn), 其中 n 为给定数组的长度。我们需要 O(nlogn) 的时间进行排序,以及 O(n) 的时间遍历数组,因此总时间复杂度为 O(nlogn)
  • 空间复杂度: O(n), 需要额外的一个数组保存排序后的数组

参考资料

【宫水三叶】一题双解 :「双指针 + 排序」&「双指针 + 线性扫描」 - 最短无序连续子数组 - 力扣(LeetCode)

思路清晰明了,看不懂??不存在的!! - 最短无序连续子数组 - 力扣(LeetCode)

你可能感兴趣的:(LeetCode,leetcode,双指针)