zoukankan      html  css  js  c++  java
  • 单调队列

    单调队列

    作用

    • 解决滑动窗口最值问题,使得原数组每个元素最多入队和出队1次,就能够求出所有窗口的最值,避免了重复比较求最值
    • 优化其他算法

    性质

    • 以维护滑动窗口最小值为例

    • 需要构建单调递增双端队列,使得队首保存当前窗口最小值在原数列中所处的位置

    • 遍历原数组

      • 若当前值大于队尾值或者队列为空,则直接把当前值的序号插入队尾
      • 若当前值小于队尾值所指向原数组的值,则它需要挤到前面去。方法是只要当前队尾所指向的原数组的值比当前值大,就弹出队尾,直到队尾所指向的原数组的值小于当前值或者队列已经空了,再把当前值的序号插到队尾。
    • 若遍历到第i个数,窗口大小为k,只要i >= k,则每往后遍历一个数就要打印队首指向原数组的值

    • 【注意】有时候队首是不合法的,原因是队首不一定处于当前滑动窗口内部,即队首值必须处于[i-k+1 , i]之间

    STL deque 使用

        #include<iostream>
        #include<deque> 
        using namespace std;
        const int maxn = 1e6+10;
        deque<int> q;
        int a[maxn];
        int main(){
            ios::sync_with_stdio(false);
            int n,k;
            while(cin>>n>>k){
                for(int i=1; i<=n; i++) cin>>a[i];
                //最小值 维护单调增队列 
                for(int i=1; i<=n; i++){
                    //遇到更小的就往前挤 
                    while(!q.empty() && a[q.back()] > a[i] ) q.pop_back();
                    q.push_back(i);
                    //删除头 保证front的位置处于滑动窗口内 即 [i-k+1 , i] 
                    //这种情况只可能在 i>=k 时才需要考虑 
                    if(i >= k){
                        while(!q.empty() && q.front() <= i-k) q.pop_front();
                        //打印最小值
                        cout<<a[q.front()]<<" "; 
                    } 
                }
                cout<<endl;
                //q.erase(q.begin(),q.end());
                while(!q.empty()) q.pop_back();
                //最大值  维护单调减队列 
                for(int i=1; i<=n; i++){
                    //遇到大的就往前挤 
                    while(!q.empty() && a[q.back()] < a[i] ) q.pop_back();
                    q.push_back(i);
                    //删除头 保证front的位置处于滑动窗口内 即 [i-k+1 , i] 
                    //这种情况只可能在 i>=k 时才需要考虑 
                    if(i >= k){
                        while(!q.empty() && q.front() <= i-k) q.pop_front();
                        //打印最大值
                        cout<<a[q.front()]<<" "; 
                    } 
                }
                cout<<endl;
                
            }
            
        }
    
    

    数组模拟队列

        #include<iostream>
        #include<deque> 
        using namespace std;
        const int maxn = 1e6+10;
        int a[maxn];
        int b[maxn];
        int main(){
            ios::sync_with_stdio(false);
            int n,k;
            while(cin>>n>>k){
                int p=1,q=1;
                for(int i=1; i<=n; i++) cin>>a[i];
                //最小值 维护单调增队列 
                for(int i=1; i<=n; i++){
                    //遇到更小的就往前挤 
                    while(p < q && a[b[q-1]] > a[i] ) q--;
                    b[q++] = i;
                    //删除头 保证front的位置处于滑动窗口内 即 [i-k+1 , i] 
                    //这种情况只可能在 i>=k 时才需要考虑 
                    if(i >= k){
                        while(p < q && b[p] <= i-k) p++;
                        //打印最小值
                        cout<<a[b[p]]<<" "; 
                    } 
                }
                cout<<endl;
                //q.erase(q.begin(),q.end());
                p = 1 , q = 1;
                //最大值  维护单调减队列 
                for(int i=1; i<=n; i++){
                    //遇到大的就往前挤 
                    while(p < q && a[b[q-1]] < a[i] ) q--;
                    b[q++] = i;
                    //删除头 保证front的位置处于滑动窗口内 即 [i-k+1 , i] 
                    //这种情况只可能在 i>=k 时才需要考虑 
                    if(i >= k){
                        while(p<q && b[p] <= i-k) p++;
                        //打印最大值
                        cout<<a[b[p]]<<" "; 
                    } 
                }
                cout<<endl;
                
            }
            
        }
    
    
  • 相关阅读:
    MySQL分区和分布性能测试[转]
    在独立的javascript文件中获取当前项目的http路径
    解决在OFFICE平台传输数据慢的问题,使用GZIP+JSON替代WEBSERVICE提供数据
    开发流程与各层软件选型
    [转]Linux下shell的工作原理
    C# 3.0中的操作符=>
    [转]Linux用户口令的管理
    Linux基本命令篇 网络管理
    [转]Linux查看磁盘使用情况命令
    恢弘的钢琴曲《出埃及记》
  • 原文地址:https://www.cnblogs.com/czsharecode/p/10868772.html
Copyright © 2011-2022 走看看