单调队列

一、 什么是单调(双端)队列
单调队列,顾名思义,就是一个元素单调的队列,那么就能保证队首的元素是最小(最大)的,从而满足动态规划的最优性问题的需求。
单调队列,又名双端队列。双端队列,就是说它不同于一般的队列只能在队首删除、队尾插入,它能够在队首、队尾同时进行删除。
【单调队列的性质】
一般,在动态规划的过程中,单调队列中每个元素一般存储的是两个值:
1、在原数列中的位置(下标)
2、 他在动态规划中的状态值
而单调队列则保证这两个值同时单调。
从以上看,单调队列的元素最好用一个类来放,不这样的话,就要开两个数组。。。

单调队列:单调队列 即保持队列中的元素单调递增(或递减)的这样一个队列,可以从两头删除,只能从队尾插入。单调队列的具体作用在于,由于保持队列中的元素满足单调性,对手元素便是极小值(极大值)了。


http://poj.org/problem?id=2823

    //poj-2823--单调队列  
    #include<iostream>  
    #include<cstdio>  
    using namespace std;  
      
    const int MAX = 1000001;  
    //两个单调队列  
    int dq1[MAX];    //一个存单调递增  
    int dq2[MAX];    //一个存单调递减  
    int a[MAX];  
      
    inline bool scan_d(int &num)  //  这个就是 加速的 关键了     
    {  
        char in;bool IsN=false;  
        in=getchar();  
        if(in==EOF)  
            return false;  
        while(in!='-'&&(in<'0'||in>'9')) in=getchar();  
        if(in=='-')   { IsN=true;num=0;}  
        else num=in-'0';  
        while(in=getchar(),in>='0'&&in<='9')  
        {  
            num*=10,num+=in-'0';  
        }  
        if(IsN)  
            num=-num;  
        return true;  
    }  
      
    int main(void)  
    {  
        int i,n,k,front1,front2,tail1,tail2,start,ans;  
      
        while(scanf("%d %d",&n,&k)!=EOF)  
        {  
            for(i = 0 ; i < n ; ++i)  
                scan_d(a[i]);  
            front1 = 0, tail1 = -1;  
            front2 = 0, tail2 = -1;  
            ans = start = 0;  
            for(i = 0 ; i < k ; ++i)  
            {  
                while(front1 <= tail1 && a[ dq1[tail1] ] <= a[i])   //当前元素大于单调递增队列的队尾元素的时候,队尾的元素依次弹出队列,直到队尾元素大于当前当前元素的时候,将当前元素插入队尾  
                    --tail1;  
                dq1[ ++tail1 ] = i;    //只需要记录下标即可  
      
                while(front2 <= tail2 && a[ dq2[tail2] ] >= a[i])   //当前元素小于单调递减队列的队尾元素的时候,队尾的元素依次弹出队列,直到队尾元素小于当前当前元素的时候,将当前元素插入队尾  
                    --tail2;  
                dq2[ ++tail2 ] = i;    //只需要记录下标即可  
            }  
            printf("%d ",a[ dq2[ front2 ] ]);  
            for( ; i < n ; ++i)  
            {  
                while(front2 <= tail2 && a[ dq2[tail2] ] >= a[i])  
                    --tail2;  
                dq2[ ++tail2 ] = i;   
                while(dq2[ front2 ] <= i - k)  
                    ++front2;  
                if(i != n-1)  
                    printf("%d ",a[ dq2[ front2 ] ]);  
            }  
            printf("%d\n",a[ dq2[ front2 ] ]);  
              
            //输出最大值  
            printf("%d ",a[ dq1[ front1 ] ]);  
            for(i=k ; i < n ; ++i)  
            {  
                while(front1 <= tail1 && a[ dq1[tail1] ] <= a[i])  
                    --tail1;  
                dq1[ ++tail1 ] = i;   
                while(dq1[ front1 ] <= i - k)  
                    ++front1;  
                if(i != n-1)  
                    printf("%d ",a[ dq1[ front1 ] ]);  
            }  
            printf("%d\n",a[ dq1[ front1 ] ]);  
        }  
        return 0;  
    }  

http://acm.hdu.edu.cn/showproblem.php?pid=3530   Subsequence

    /* 
    题意:给出一个序列,求最长的连续子序列,使得 M<=Max-Min<=K 
           n <= 10^5 
    依次枚举剩下的N-1个元素,并且将当前未入队的第一个元素和队尾元素比较,当且仅当队列为非空并且队尾元素的值小于当前未入队的元素时, 
    将队尾元素删除(也就是队尾指针-1),因为当前的元素比队尾元素大,所以在区间内队尾元素不会是最大值了。 
    重复这个过程直到队列空或者队尾元素比当前元素大, 
    */  
    #include<iostream>  
    #include<cstdio>  
    using namespace std;  
      
    const int MAX = 100001;  
    //两个单调队列  
    int dq1[MAX];    //一个存单调递增  
    int dq2[MAX];    //一个存单调递减  
    int a[MAX];  
      
    inline bool scan_d(int &num)  //  这个就是 加速的 关键了     
    {  
        char in;bool IsN=false;  
        in=getchar();  
        if(in==EOF)  
            return false;  
        while(in!='-'&&(in<'0'||in>'9')) in=getchar();  
        if(in=='-')   { IsN=true;num=0;}  
        else num=in-'0';  
        while(in=getchar(),in>='0'&&in<='9')  
        {  
            num*=10,num+=in-'0';  
        }  
        if(IsN)  
            num=-num;  
        return true;  
    }  
      
    int main(void)  
    {  
        int i,n,m,k,front1,front2,tail1,tail2,start,ans;  
        while(scanf("%d %d %d",&n,&m,&k) != EOF)  
        {  
            for(i = 0 ; i < n ; ++i)  
                scan_d(a[i]);  
            front1 = 0, tail1 = -1;  
            front2 = 0, tail2 = -1;  
            ans = start = 0;  
            for(i = 0 ; i < n ; ++i)  
            {  
                while(front1 <= tail1 && a[ dq1[tail1] ] <= a[i])   //当前元素大于单调递增队列的队尾元素的时候,队尾的元素依次弹出队列,直到队尾元素大于当前当前元素的时候,将当前元素插入队尾  
                    --tail1;  
                dq1[ ++tail1 ] = i;    //只需要记录下标即可  
      
                while(front2 <= tail2 && a[ dq2[tail2] ] >= a[i])   //当前元素小于单调递减队列的队尾元素的时候,队尾的元素依次弹出队列,直到队尾元素小于当前当前元素的时候,将当前元素插入队尾  
                    --tail2;  
                dq2[ ++tail2 ] = i;    //只需要记录下标即可  
      
                /* 
                Max - Min 为两个队列的队首之差 
                while(Max-Min>K)  看哪个的队首元素比较靠前,就把谁往后移动 
                */  
                while(a[ dq1[front1] ] - a[ dq2[front2] ] > k)  
                {  
                    if(dq1[front1] < dq2[front2] )  
                    {  
                        start = dq1[front1] + 1;  
                        ++front1;  
                    }  
                    else  
                    {  
                        start = dq2[front2] + 1;  
                        ++front2;  
                    }  
                }  
                if(a[ dq1[front1] ] - a[ dq2[front2] ] >= m)  
                {  
                    if(i - start +1 > ans)  
                        ans = i - start + 1;  
                }  
            }  
            printf("%d\n",ans);  
        }  
        return 0;  
    }  

原文:http://blog.csdn.net/hackbuteer1/article/details/7424466

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python的单调队列是一种用于解决某些特定问题的数据结构。它是队列的一种变体,可以快速查询当前队列中的最大或最小元素。 单调队列通常用于需要维护当前滑动窗口中的最大或最小值的情况。例如,假设我们有一个长度为n的数组arr和一个窗口大小为k的滑动窗口。我们想要找到每个窗口中的最大值。单调队列就可以帮助我们在O(n)的时间复杂度内实现。 实现单调队列需要两个操作:push(x)和pop()。push(x)用于向队列的尾部添加元素x,而pop()用于从队列的头部删除元素。这两个操作具有O(1)的时间复杂度。 当我们向队列中添加一个新元素时,为了维护队列单调性,我们需要从队列的尾部删除一些元素。具体来说,我们从队列的尾部开始,不断地删除比新元素小的元素,直到队列为空或者新元素大于等于队列尾部元素为止。这样,我们就可以保证队列中的元素是以递减顺序排列的。 当我们需要查询当前队列中的最大或最小值时,只需访问队列头部的元素即可。由于队列中的元素是以递减的顺序排列的,所以头部元素就是最大值(或最小值)。 总的来说,Python的单调队列是一种高效的数据结构,可以用于解决一些特定问题,如滑动窗口中的最大(或最小)值。它具有O(n)的时间复杂度,并且可以通过push(x)和pop()操作来维护队列单调性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值