dequeue双向队列
dequeue<int>que;//创建双向队列
que.push_front()//在队列前面塞一个元素
que.push_back()//在队列后面塞一个元素
que.pop_front()//删除队列第一个元素
que.pop_back()//删除队列的最后一个元素
que.clear()//清空队列
que.empty()//判断是否为空
que.size()//返回队列元素个数
单调队列
问题:
对每个长度为k的滑动窗体,求其最大值和最小值
思路1:
使出秘技dequeue (STL赛高!)
这里根据雨巨生动形象的例子,我来简单描述一下下:
题意:给出各届acmer的实力,众所周知大学基本上是四年,所以我们滑动窗口的大小就是4,问每个窗口中实力最强与最弱的是多少
举个样例:1 4 6 3 3 3 2
我们现在先求最大值,最小值在最大值的基础上改一改就行。
首先我们看给1入队列(是dequeue,后面不赘述),因为没到达四个元素,所以不输出,再到第二个元素4,大于1,说明在4的伟大作用下,1已经废了,就直接扔出去,也就是“去尾”,得到队列 4 。再到6,6 > 4,所以在6的存在下,4 废了,扔出去,得到队列 6。再到3,3 小于6,说明他有机会,因为可以等到6的退役了(也就是6滑出窗口了),他就可能是最大的,把 3塞进去,得到6,3的队列,现在达到窗口的大小,所以输出队头6,再看3,等于队列尾的元素,就把他也塞进去,再输出一个6,下一个3塞进来以后,我们判断发现队列头还没有出窗口,就再输出6,到了2,塞进去,发现6已经出了窗口,就得“去头”,所以输出3
总结一下,实现单调队列,主要分四个部分:
- 去尾:队尾元素出队列。当有新的acmer等待入队时,需要从队尾开始判断会不会破坏队的单调性,会的话就去尾。
- 入队:将新队员从队尾塞进来
- 去头:队头元素出队列。当acmer满四年后就得退役,也就是要将其扔出队列
- 取解:取队头元素
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <stdlib.h>
#include <sstream>
#include <map>
#include <set>
using namespace std;
#define inf 0x3f3f3f3f
#define MAX 1000000 + 5
typedef long long ll ;
inline int IntRead(){//int的快读
char ch = getchar();
int s = 0, w = 1;
while(ch < '0' || ch > '9'){
if(ch == '-') w = -1;
ch = getchar();}
while(ch >= '0' && ch <= '9'){
s = s * 10 + ch - '0';
ch = getchar();}
return s * w;
}
int tr[MAX];
int main()
{
int n, k;
deque<int>q;//双向队列
cin>>n>>k;
for(int i = 1; i <= n; i++)
tr[i] = IntRead();
for(int i = 1; i <= n; ++i){
while (!q.empty() && tr[i] < tr[q.back()]) {
q.pop_back();//去尾
}
q.push_back(i);//入队
if(i >= k){//从第k个开始,后面都得输出
while (!q.empty() && i - q.front() + 1 > k) {
q.pop_front();//去头
}
if(i == k) cout<<tr[q.front()];//控制空格的输出
else cout<<' '<<tr[q.front()];
}
}
cout<<endl;
q.clear();//清空队列
for(int i = 1; i <= n; i++){
while (!q.empty() && tr[q.back()] < tr[i]) {
q.pop_back();
}
q.push_back(i);
if(i >= k){
while (!q.empty() && i - q.front() + 1 > k) {
q.pop_front();
}
if(i == k)
cout<<tr[q.front()];
else
cout<<' '<<tr[q.front()];
}
}
cout<<endl;
}
思路2:
手写队列
head代表队列头,tail代表队列尾
结构体的q数组即为“双向队列”,其id用来记录下标,val来记录值
还是那四步,去尾入队去头取解。
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <stdlib.h>
#include <sstream>
#include <map>
#include <set>
using namespace std;
#define inf 0x3f3f3f3f
#define MAX 1000000 + 5
typedef long long ll ;
inline int IntRead(){//int的快读
char ch = getchar();
int s = 0, w = 1;
while(ch < '0' || ch > '9'){
if(ch == '-') w = -1;
ch = getchar();}
while(ch >= '0' && ch <= '9'){
s = s * 10 + ch - '0';
ch = getchar();}
return s * w;
}
int tr[MAX], n, k;
struct ran{
int id, val;
}q[MAX];
void getmin(){
int head = 1, tail = 0;//初始化
for(int i = 1; i <= n; ++i){
while (head <= tail && tr[i] < q[tail].val) tail--;//去尾
q[++tail].id = i;//入队的时候记得要记录两部分
q[tail].val = tr[i];
while (i - q[head].id + 1 > k) head++;//去头
if(i >= k){
if(i == k)cout<<q[head].val;//控制空格,防止PE
else cout<<' '<<q[head].val;
}
}
cout<<endl;
}
void getmax(){
int head = 1, tail = 0;
for(int i = 1; i <= n; ++i){
while (head <= tail && q[tail].val < tr[i]) tail--;
q[++tail].id = i;
q[tail].val = tr[i];
while (i - q[head].id + 1 > k) head++;
if(i >= k){
if(i == k)cout<<q[head].val;
else cout<<' '<<q[head].val;
}
}
cout<<'\n';
}
int main()
{
cin>>n>>k;
for(int i = 1; i <= n; ++i) tr[i] = IntRead();
getmin();
getmax();
return 0;
}
我看了一下这两个的时间差的不多,2ms,我感觉还是dequeue好写一些,嘎嘎,感觉写成函数更美观一点哎=(.)=
简单的数据结构
对dequeue的熟练运用
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <stdlib.h>
#include <sstream>
#include <map>
#include <set>
using namespace std;
#define inf 0x3f3f3f3f
#define MAX 1000000 + 5
typedef long long ll ;
inline int IntRead(){//int的快读
char ch = getchar();
int s = 0, w = 1;
while(ch < '0' || ch > '9'){
if(ch == '-') w = -1;
ch = getchar();}
while(ch >= '0' && ch <= '9'){
s = s * 10 + ch - '0';
ch = getchar();}
return s * w;
}
int main()
{
int n, m, k, j;
n = IntRead();
m = IntRead();
deque<int>q;
for(int i = 1; i <= m; ++i){
k = IntRead();
if(k == 1){
j = IntRead();
q.push_front(j);
}
else if(k == 3){
j = IntRead();
q.push_back(j);
}
else if(k == 2) q.pop_front();
else if(k == 4) q.pop_back();
else if(k == 5) reverse(q.begin(), q.end());//容器反转
else if(k == 6){
cout<<q.size()<<endl;
deque<int>::iterator it;
for(it = q.begin(); it != q.end(); it++){
if(it != q.begin()) cout<<' ';
cout<<*it;
}
/*
auto的做法,比std慢了些
for(auto it = q.begin(); it != q.end(); it++){
if(it != q.begin()) cout<<' ';
cout<<*it;
}
*/
cout<<endl;
}
else if(k == 7){//支持排序
sort(q.begin(), q.end());
}
}
return 0;
}