• 单调队列 Monotonic Queue应用:leetcode(未完待续)


    239. Sliding Window Maximum

    581: https://leetcode.com/problems/shortest-unsorted-continuous-subarray/

    862: https://leetcode.com/problems/shortest-subarray-with-sum-at-least-k/
    496: https://leetcode.com/problems/next-greater-element-i/
    84: https://leetcode.com/problems/largest-rectangle-in-histogram/

    239:最主要是push

    class Solution {
    public:
        //单调队列:单调递增或单调递减队列
        class MQ {
                deque<pair<int,int>> mq;
                //first为数组下标。second为push该数时前面remove掉的数的个数(保持MQ中第一个元素为最大值,可能会pop掉之前的好几个元素)
                //那么,每次在front_pop时,second为0,才会pop该元素,否则,second-1(其实可以理解second为队列中总的元素数)
            public:
                void push(int val){
                    //如果为空队列,直接push
                    if(mq.empty()){
                        mq.push_back(make_pair(val,0));
                        return ;
                    } 
                    //双端队列不为空,remove掉前面小于该val的数,保证最大的为队头.
                    //而且保证队列中为递减,只保留最大、次大。。。
                    //3 1 在队列,现在push 2: 如何做?
                    int cnt = 0;
                    while(!mq.empty() && mq.back().first < val){
                        cnt = cnt + mq.back().second+1;
                        mq.pop_back();
                    }
                    mq.push_back(make_pair(val,cnt));
                }
                //pop的时候,pop队头,但是要保证队头元素的second属性为0.
                void pop(){
                    if(!mq.empty() && mq.front().second){
                        mq.front().second--;
                        return ;
                    }
                    if(!mq.empty())  mq.pop_front();
                }
                int getMax(){
                    return mq.front().first;
                }
        };
        
        vector<int> maxSlidingWindow(vector<int>& nums, int k) {
            //每一次push,getMax,pop
            int n = nums.size();
            vector<int> res;
            deque<pair<int,int>> dq;
            MQ mq;
            for(int i=0;i<n;i++){
                mq.push(nums[i]);
                if(i >= k-1){
                    res.push_back(mq.getMax());
                    mq.pop();
                } 
            }
            return res;
        }
    };

    So we maintain a monotonic array with index increasing and value decreasing, because smaller elements like A[l] on the left are useless.

    For example, with sliding window of fixed length 3,

     A = [3, 1, 4, 3, 8] => monotonic queue is like [3], [3, 1], [4], [4, 3], [8]

    when element 4 enters, we remove [3, 1] because they are on the left and smaller than 4, no chance being chosen as the max element.

    The head of the increasing queue is the running max!

    class Solution {
    public:
        //mq存nums数组下标
        vector<int> maxSlidingWindow(vector<int>& nums, int k) {
            deque<int> mq;
            vector<int> res;
            int n = nums.size();
            for(int i=0;i<n;i++){
                if(!mq.empty() && i-mq.front() >=k) mq.pop_front();
                //push进去
                while(!mq.empty() && nums[mq.back()] < nums[i]){
                    mq.pop_back();
                }
                mq.push_back(i);
                if(i >= k-1) res.push_back(nums[mq.front()]);
            }
            return res;
        }
    };

    581: 最短无序连续子数组

    class Solution {
    public:
        //基本方法利用排序,前后进行数组对比
        int findUnsortedSubarray(vector<int>& nums) {
            int n = nums.size();
            int res = n;
            int s=n,e=-1;
            //1 3 5 6 7 2 8 9
            //超时,优化。s:位于数组中最左边的其后有元素小于nums[s]的位置,e:位于数组最右边其前有元素大于nums[e]的位置
            // for(int i=0;i<n;i++){
            //     for(int j=i+1;j<n;j++){
            //         if(nums[i] > nums[j]) {
            //             s = i;
            //             e = j;
            //         }
            //         if(s != e){
            //             start.push_back(s);
            //             end.push_back(e);
            //         }
            //     }
            // }
            //return start.size()==0 ? 0:*max_element(end.begin(),end.end())-start.front()+1;
            //利用栈: 找出最左和左右位置。
            //当nums[j] >= 栈顶 一直push(升序),当num[j] < 栈顶开始pop直到num[j]>栈顶,此时栈顶位置为s(所有都遍历完)
            //同理:反序一遍找e
            stack<int> sta;
            for(int i=0;i<n;i++){
                while(!sta.empty() && nums[i] < nums[sta.top()]) {
                    s = min(s,sta.top());
                    sta.pop();
                }
                sta.push(i);
            }
            while(!sta.empty()) sta.pop();
            for(int i=n-1;i>=0;i--){
                while(!sta.empty() && nums[i] > nums[sta.top()]) {
                    e = max(e,sta.top());
                    sta.pop();
                }
                sta.push(i);
            }
            return s-e >n ? 0 : e-s+1;
        }
    };

    上述算法O(N) spce,time

    优化:找出无序数组部分的最小值和最大值,再找到小于最小值的位置和大于最大值的位置(直接即为无序部分)

    我们再次遍历 numsnums 数组并通过与其他元素进行比较,来找到 minmin 和 maxmax 在原数组中的正确位置。我们只需要从头开始找到第一个大于 minmin 的元素,从尾开始找到第一个小于 maxmax 的元素,它们之间就是最短无序子数组。

    class Solution {
    public:
        //找数组中无序部分最小与最大
        //再找到小于min的位置,大于max的位置
        int findUnsortedSubarray(vector<int>& nums) {
            int beg = -1,end = -2;
            int n = nums.size();
            int mn = INT_MAX,mx = INT_MIN;
            int flag = false;
            for(int i=1;i<n;i++){
                if(nums[i] < nums[i-1]) flag = true;
                //后面都是无序部分
                if(flag){
                    if(nums[i] < mn) mn = nums[i];
                }
                
            }
            flag = false;
            for(int i=n-2;i>=0;i--){
                if(nums[i] > nums[i+1]) flag = true;
                if(flag){
                    if(nums[i] > mx) mx = nums[i];
                }
            }
            //找出小于min的位置和大于max的位置,这个位置直接都无序
            int l = n,r = -1;
            for(int i=0;i<n;i++){
                if(nums[i] > mn) l = min(l,i);
                if(nums[i] < mx) r = max(r,i);
            }
            return l-r > n ? 0:r-l+1;
        }
    };

    862: Shortest Subarray with Sum at Least K

    class Solution {
    public:
        //deque+前缀和.
        //前缀和   {pre[i] <= pre[j]-K}
        int shortestSubarray(vector<int>& A, int K) {
            int n = A.size();
            int res = n+1;
            //最主要的是首先得想到前缀和:这个问题典型的前缀和
            vector<int> pre;
            int sum = 0;
            for(int i=0;i<n;i++){
                sum += A[i];
                pre.push_back(sum);
            }
            //问题转化为:pre[j]-pre[i] >= K.即对于当前的pre[j]来说,找一个pre[i]最小,且距离j最近
            //左侧 最近最小的元素(单调递减序列)
            deque<int> dq;
            for(int i=0;i<n;i++){
                if(pre[i] >= K) res = min(res,i+1);
                //首先进行结果判断
                while(!dq.empty() && pre[i]-pre[dq.front()]>=K){
                    res = min(res,i-dq.front());
                    dq.pop_front();
                }
                //将当前pre[i] 入队尾,尾部比当前pre[i]大的元素无机会再留在队列内le
                while(!dq.empty() && pre[i] <= pre[dq.back()]){
                    dq.pop_back();
                }
                dq.push_back(i);
            }
            return res == n+1 ? -1:res;
        }
    };

    496: 

  • 相关阅读:
    c# 设计模式 之:装饰模式
    c# 设计模式 之:抽象工厂
    c# 设计模式 之:简单工厂、工厂方法、抽象工厂之小结、区别
    c# 设计模式 之:工厂模式之---工厂模式
    c# 设计模式 之:工厂模式之---简单工厂
    uml
    ASP.NET应用程序生命周期
    C语言可变参数个数
    软件开发过程中的视角
    UML类图与类的关系详解
  • 原文地址:https://www.cnblogs.com/wsw-seu/p/14019552.html
Copyright © 2020-2023  润新知