zoukankan      html  css  js  c++  java
  • 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

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

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

    从右找到第一个。

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

    好难啊,转不过弯

  • 相关阅读:
    转:Windows Socket五种I/O模型
    C++线程池的实现(二)
    C++ 简单 Hash容器的实现
    C++ TrieTree(字典树)容器的实现
    转载:C++线程池的一个实现
    C++用数组实现的静态队列
    C++ 类成员函数作为参数
    C++位操作符总结
    C++简单单例模式
    C++控制程序只运行一个实例
  • 原文地址:https://www.cnblogs.com/weizhibin1996/p/9973241.html
Copyright © 2011-2022 走看看