单调队列

单调队列指的是队列中的所有元素是单调递增或者单调递减的。

它可以在队首或队尾删除元素,只能在队尾插入元素,维护队列的均摊时间复杂度为O(1)。

单调队列一般用于解决的问题如,用一个长度为k的框在所给序列上移动,求框里面所包含的元素的最大值。

以单调递减队列为例:

队尾插入元素:为了保证队列的递减性,在插入元素num的时候,要将队尾元素和num比较,如果队尾元素不大于num,则删除队尾元素,然后继续将新的队尾元素与num比较,直到队尾元素大于num,这个时候我们才将num插到队尾。

队首删除元素:其实本质上我们只需要保存包括当前元素i在内的前k个元素中的最大值,所以当队首元素的下标小于i - k + 1的时候,就说明当前队首元素的存在已经没有意义了,要将队首元素删除。


核心代码(法一):

int n, k;  
int a[100005],queue[100005];  
void minQueue() {  
    int head = 1, tail = 0;  
    queue[head] = 1;  
    for (int i = 0; i < n; i++) {  
        //删除队首元素  
        if (i - queue[head] == k) head++;  
        //直接放在队尾  
        if (head - tail == 1 || a[i] > a[queue[tail]]) {//第一个条件指的是队列为空  
            queue[++tail] = i;  
        }  
        else {//不断删除队尾元素找到合适位置  
            while (tail >= head && a[i] <= a[queue[tail]]) {  
                tail--;  
            }  
            queue[++tail] = i;  
        }  
        if (i >= k - 1) {  
            printf("%d%c", a[queue[head]], i == n - 1 ? '\n' : ' ');  
        }  
    }  
}  
void maxQueue() {  
    int head = 1, tail = 0;  
    queue[head] = 1;  
    for (int i = 0; i < n; i++) {  
        //删除队首元素  
        if (i - queue[head] == k) head++;  
        //直接放在队尾  
        if (head - tail == 1 || a[i] < a[queue[tail]]) {//第一个条件指的是队列为空  
            queue[++tail] = i;  
        }  
        else {//不断删除队尾元素找到合适位置  
            while (tail >= head && a[i] >= a[queue[tail]]) {  
                tail--;  
            }  
            queue[++tail] = i;  
        }  
        if (i >= k - 1) {  
            printf("%d%c", a[queue[head]], i == n - 1 ? '\n' : ' ');  
        }  
    }  
}  
核心代码(法二):

int n, k;  
int a[100005];//原序列   
int minQueue[100005],maxQueue[100005];//单调递减队列 单调递增队列  
int minRe[100005],maxRe[100005];//结果   
void solve() {  
    int minHead = 1, minTail = 0;//单调递减序列头、尾   
    int maxHead = 1, maxTail = 0;//单调递增序列头、尾   
    for (int i = 0; i < n; i++) {  
        //处理单调递减序列   
        while (minTail >= minHead && a[i] <= a[minQueue[minTail]]) {  
            minTail--;  
        }  
        minQueue[++minTail] = i;  
        if(i - minQueue[minHead] == k) minHead++;  
        //处理单调递增序列   
        while (maxTail >= maxHead && a[i] >= a[maxQueue[maxTail]]) {  
            maxTail--;  
        }  
        maxQueue[++maxTail] = i;  
        if(i - maxQueue[maxHead] == k) maxHead++;  
        //存储结果   
        if(i >= k - 1){  
            minRe[i] = a[minQueue[minHead]];  
            maxRe[i] = a[maxQueue[maxHead]];  
        }  
    }  
    //打印结果  
    for(int i = k - 1;i < n;i++){  
        printf("%d%c",minRe[i],i == n - 1?'\n':' ');  
    }  
    for(int i = k - 1;i < n;i++){  
        printf("%d%c",maxRe[i],i == n - 1?'\n':' ');  
    }   
}  



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值