POJ2823

来源:互联网 发布:360手柄淘宝 编辑:程序博客网 时间:2024/06/06 15:04

滑动窗口单调队列解法

单调递减队列:单调队列的头元素一直是队列当中的最大值,而且队列中的值是按照递减的顺序排列的。我们可以从队列的末尾插入一个元素,可以从队列的两端删除元素。

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

2.队尾的删除刚刚已经说了,那么队首的元素什么时候删除呢?由于我们只需要保存i的前k-1个元素中的最大值,所以当队首的元素的索引或下标小于i-k+1的时候,就说明队首的元素对于求f(i)已经没有意义了,因为它已经不在窗里面了。所以当index[队首元素]<i-k+1时,将队首元素删除。

题意:用一个长度为k的窗在整数数列上移动,求窗里面所包含的数的最大值

题解:维护两个单调队列,一个递增的单调队列存放区间最大值,一个递减的单调队列存放区间最小值就能解决问题

PS:STL的list与deque都能模拟双向队列,但deque的时间效率会更高

#include <stdio.h>#include <iostream>#include <deque>#include <cmath>#define MAX 1000005using namespace std ;int num[MAX];int main(){int n , k ;scanf("%d%d",&n,&k) ;for(int i = 0 ; i < n ; i ++) scanf("%d",&num[i]) ;deque<int> minque ;deque<int> maxque ;for(int i = 0 ; i < k-1 ; i ++ ){while(!minque.empty() && num[minque.back()] > num[i]){minque.pop_back();}minque.push_back(i) ;}for(int i = k-1 ; i < n ; i ++){while(!minque.empty() &&(minque.front() - i + 1 > k ||i - minque.front()  + 1 > k))            minque.pop_front() ;while(!minque.empty() &&num[minque.back()] > num[i])        {            minque.pop_back();        }minque.push_back(i) ;if(i == n-1) printf("%d\n",num[minque.front()]);else printf("%d ",num[minque.front()]) ;}for(int i = 0 ; i < k-1 ; i ++ ){while(!maxque.empty() && num[maxque.back()] < num[i]){maxque.pop_back();}maxque.push_back(i) ;}for(int i = k-1 ; i < n ; i ++){while(!maxque.empty() &&(maxque.front() - i + 1 > k ||i - maxque.front()  + 1 > k))            maxque.pop_front() ;while(!maxque.empty() &&num[maxque.back()] < num[i])        {            maxque.pop_back();        }maxque.push_back(i) ;if(i == n-1) printf("%d\n",num[maxque.front()]);else printf("%d ",num[maxque.front()]) ;}return 0 ;}



0 0
原创粉丝点击