今日刷题

78 阅读1分钟

每日刷题(一)

581. 最短无序连续子数组

思路1:

对于不需要排序的元素来说。它后面的元素一定更大,前面的元素一定更小。因此可以使用双指针。指针分别从0和length-1向中间移动,遍历数组,遇到了不满足前面条件的元素就是需要排序的元素,指针不再移动。

var findUnsortedSubarray = function(nums) {
    if(nums.length<=1){return 0;}
    let l=0;
    let r=nums.length-1;
    function needSort(index){
        for(let i=0;i<index;i++){
            if(nums[i]>nums[index]){
                return true;
            }
        }
        for(let i=index+1;i<nums.length;i++){
            if(nums[i]<nums[index]){
                return true;
            }
    }
    return false;
    }
    let left=-1;
    let right=-1;
    while(l<nums.length&&r>=0){
    if(needSort(l)&&left===-1){
       left=l;
    }
    if(needSort(r)&&right===-1){
        right=r
    }
    if(left!==-1&&right!==-1){
        break;
    }
        l++;
        r--;
    }
    return right!==left? right-left+1:0;
};

分析:判断元素是否需要排序要进行循环 ,双指针比较还需要循环,时间复杂度O(MN),N为数组的长度,M为N-最短无序子数组的长度,空间复杂度为O(1)

思路2:

先深度拷贝数组并进行排序,将排序后的数组与原数组进行比较,同样使用双指针从两端往中间遍历

var findUnsortedSubarray = function(nums) { 
    if (isSorted(nums)) { return 0; } 
    const numsSorted = nums.concat([]).sort((a, b) => a - b); 
    let left = 0; 
    while (nums[left] === numsSorted[left]) { left++; } 
    let right = nums.length - 1; 
    while (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),保存的数组

思路3:

在思路1的基础上,我们不需要对每个元素进行单独的循环去判断是否需要排序。而是设定maxL和minR,表示从前往后遍历过的左边区域的最大值和从后往前遍历右边区域的最小值。从后往前遍历时,如果一个元素比minR的值大,说明这个元素就需要排序,把这个元素设为right,否则把这个值设minR遍历到最后,最后一个right就是最短无序子数组的右边界;同理,从前往后遍历时,如果一个元素比maxL的值要小,说明这个元素就需要排序。

var findUnsortedSubarray = function(nums) {
    const n = nums.length;
    if(n<=1){return 0;}
    let right = -1;//从左往右移动的指针
    let left = -1; //从右往左移动的指针
    let minR=Number.MAX_VALUE;
    let maxL= -Number.MAX_VALUE;
    for(let i=0;i<n;i++){
        if(nums[i]<maxL){
            right=i;
        }else{
            maxL=nums[i]
        }
        if(nums[n-1-i]>minR){
            left=n-1-i;
        }else{
            minR=nums[n-1-i]
        }
    }
    return right === left ? 0 : right-left + 1;
};

分析:时间复杂度:O(n),因为需要遍历数组一次;空间复杂度:O(1),因为只需要常数的空间保存若干变量。