LeetCode581-最短无序子数组(滑动窗口)

JS做题爽就爽在不用开编辑器

这个题目比较难,毕竟最后是用了On级别的算法

做了下去看来大体上是对的,但是很多地方的小细节出了很多差错,因为是在很困的情况下做的题目

主要就是找到一个窗口,里面最小的数字往左挪动,右边最大的数字往右挪。

不需要真实的交换,只是简单的比较即可。

1、窗口里面的重复数字怎么办? 不用管,因为窗口里面有他们的位置,只需要找一个代表出去即可。

2、数组里的重复数字怎么办?如果是降序的,就把它放到窗口里面。 比如3,2,2,2,2,2 这些2要全部进去。

3、往左往右挪,会不会导致把更小或更大的数组弄进窗口?

不会。

往左移动可能会有比窗口里面更大的数字,因为是降序找到这个最小数字的。

往右移动不会有小于最小值的数字,假如右边有小于最小值的数字,那么窗口里面的数字全都比它大,它也是降序,也会被拉到窗口里面的。

反证法很重要。

/**
 * @param {number[]} nums
 * @return {number}
 */
var findUnsortedSubarray = function(nums) {
    
    if(nums.length == 1){
        return 0;
    }
    
    if(nums.length == 2){
        if(nums[0]>nums[1]){
            return 2;
        }else{
            return 0;
        }
    }
    
    // 滑动窗口,找到不合理的数字的范围吧,顺便记录里面的最大最小值,以及下标,因为最大最小值关系着子数组的大小
    // 最小的一直往左交换位置,最大的一直往右交换位置,最后这个位置之差就是了
    // 最大的数往右边交换,不会把小于最小的数换进来,因为如果右边存在小于最小的数,那么这个数当初肯定也会被纳入到滑动窗口里面去的
    // 倒是最左边可能换入比最大还大的数,所以先弄好最小的数字开始
    // 还可能有重复元素,比如题目的9<10,不过10会一直换到最后,应该还好
    // 但是最小和最大的数字可能会有多个,不过好像这些重复数字会在滑动窗口里有他们的位置,所以不用管
    let low = -1,high = -1;
    
    // 如果当前值是降序,就是ture,用来记录重复的数字[1,3,2,2,2] 4
    let flag = false;
    
    let last = nums[0];
    
    for(let i=1;i<nums.length;i++){
        if(nums[i]<last){
            if(low===-1){
                // 应该把前一个也算进来
                low=i-1;
                // 第一次就要给high赋值
                high = i;
            }else{
                //high很有可能不会被赋值 如果中途只有一个降序[1,3,2,4,5]
                high=i;
            }
        
            flag = true;
                
        }else if(nums[i]===last){
            if(flag){
                high=i;
            }
        }else{
            flag=false;
        }
        
        last = nums[i];
        
    }
    
    // console.log(low,high);

    
    
    // 找到最小和最大的数字
    // 数组的内容可以使正负数
    let min = nums[low];
    let max = nums[low];
    for(let i=low;i<=high;i++){
        if(nums[i]<min){
            min=nums[i];
        }
        if(nums[i]>max){
            max=nums[i];
        }
    }
    
    // console.log(min,max);
    
    
    // 一直挪左边的
    // 直接和窗口外面的比即可
    //窗口外面要么是重复数字,要么是升序排好的,如果遇到比自己还小或相等的,就是应该退出了
    for(let i =low-1;i>=0;i--){
        if(min<nums[i]){
            low--;
            if(nums[i]>max){
                max=nums[i];
            }
        }else{
            break;
        }
    }
    

    // 挪右边的
    for(let i=high+1;i<nums.length;i++){
        if(max>nums[i]){
            high++;
        }else{
            break;
        }
    }
    
    // console.log(low,high);
    
    if(high===low){
        return 0;
    }else{
        return high-low+1;    
    }
    
    //[2,1] 2  0
    // 如果整个数组是逆序的,这个方法不行啊
    // [3,2,1]应该可以,2是low,1是high
    // [-1,-1,-1,-1]
        
    
    
    
};

时间还行

百度了一下,有一种简单的做法。

先用一个辅助数组保存,然后将辅助数组排序,辅助数组里面,肯定会有一部分数字和原来的不一样。

1,2,3【】,8,9

那么这个【】其实就是子数组的大小....因为,确实,按照我的方式,往左往右挪了之后的数组,也是这样

然后从左找到第一个不同的数字

从右找到第一个。

【】就是源数组里面,乱序的数字再正确排序下,应该在的范围。

好难啊,转不过弯

原文地址:https://www.cnblogs.com/weizhibin1996/p/9973241.html