算法竞赛第一章-队列
1、队列
const int N=1e5; //定义队列大小
int que[N], head,tail; //队头队尾指针,队列大小为tail-head+1
//head++; 弹出对头,head<=tail
//queue[head]; //读对头数据
//que[++tail] = data; //数据data入队,尾指针加1,注意不能溢出
2、STL queue
- queue <Type>q:定义队列,Type为数据类型,如int、float、char等
- q.push(item):把item放进队列
- q.front():返回队首元素,但不会删除
- q.pop():删除队首元素
- q.back():返回队尾元素
- q.size():返回元素个数
- q.empty():检查队列是否为空
#include <bits/stdc++.h>
using namespace std;
int Hash[1003]={0};
queue<int>mem;
void solve(){
int m, n; cin>>m>>n;
int cnt=0; //查词典的次数
while(n--){
int en; cin>>en; //输入一个英文单词
if(!Hash[en]){ //如果内存中没有这个单词
++cnt;
mem.push(en); //单词入队列,放到队列尾部
Hash[en]=1; //记录内存中有这个单词
while(mem.size()>m){ //内存满了
Hash[mem.front()]=0; //从内存中去掉这个单词
mem.pop(); //从对头去掉
}
}
}
cout<<cnt<<"\n";
return;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
solve();
return 0;
}
3、手写循环队列
循环队列的结构体
#define N 1003
int Hash[N]={0};
struct myqueue{
int data[N];
int head, rear;
bool init(){
head=rear=0;
return true;
}
int size(){return (rear-head+N)%N;}
bool empty(){
if(size()==0) return true;
else return false;
}
bool push(int e){
if((rear+1)%N==head) return false;
data[rear]=e;
rear=(rear+1)%N;
return true;
}
bool pop(int &e){
if(head==rear) return false;
e=data[head];
head=(head+1)%N;
return true;
}
int front(){return data[head];}
}Q;
例题的完整代码
#include <bits/stdc++.h>
using namespace std;
#define N 1003
int Hash[N]={0};
struct myqueue{
int data[N];
int head, rear;
bool init(){
head=rear=0;
return true;
}
int size(){return (rear-head+N)%N;}
bool empty(){
if(size()==0) return true;
else return false;
}
bool push(int e){
if((rear+1)%N==head) return false;
data[rear]=e;
rear=(rear+1)%N;
return true;
}
bool pop(int &e){
if(head==rear) return false;
e=data[head];
head=(head+1)%N;
return true;
}
int front(){return data[head];}
}Q;
void solve(){
Q.init();
int m,n; cin>>m>>n;
int cnt=0;
while(n--){
int en; cin>>en;
if(!Hash[en]){
++cnt;
Q.push(en);
Hash[en]=1;
while(Q.size()>m){
int tmp; Q.pop(tmp);
Hash[tmp]=0;
}
}
}
cout<<cnt<<'\n';
return;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
solve();
return 0;
}
4、 双端队列
双端队列是一种不是很规矩的队列,双端队列是一种具有队列和栈性质的数据
手写数组模拟
#define N 1003
int queue[N], head, rear; //对头队尾指针,队列大小为tail-head+1
//弹出对头head++;
//queue[--head]=data; //数据入对头,注意不能溢出
//q[head]; //读队头数据
//tail--; //弹出队尾
//que[++tail]=data; //数据入队尾,注意也不能溢出
stl中的dequeue
deque<int>dq;
//dq[i]:返回队列中下标为i的元素
//dq.front():返回队头
//dq.back():返回队尾
//dq.pop_back():删除队尾,不返回值
//dq.pop_front():删除队头,不返回值
//dq.push_back(e):在队尾添加一个元素e
//dq.push_front(e):在对头添加一个元素e
滑动窗口
P1186洛谷传送门
#include <bits/stdc++.h>
using namespace std;
const int N=1000005;
int a[N];
deque<int>q;
void solve(){
int n,m; cin>>n>>m;
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);
if(i>=m){
while(!q.empty()&&q.front()<=i-m) q.pop_front();
cout<<a[q.front()]<<' ';
}
}
cout<<'\n';
while(!q.empty()) q.pop_front();
for(int i=1;i<=n;++i){
while(!q.empty()&&a[q.back()]<a[i]) q.pop_back();
q.push_back(i);
if(i>=m){
while(!q.empty()&&q.front()<=i-m) q.pop_front();
cout<<a[q.front()]<<' ';
}
}
cout<<'\n';
return;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
solve();
return 0;
}
5、单调队列
单调队列解决有长度限制的最大子段和问题
#include <bits/stdc++.h>
using namespace std;
const int N=1000005;
int s[N];
deque<int>dq;
void solve(){
int n,m; cin>>n>>m;
for(int i=1;i<=n;++i) cin>>s[i];
for(int i=1;i<=n;++i) s[i]=s[i]+s[i-1]; //计算前缀和
int ans=-1e8;
dq.push_back(0);
for(int i=1;i<=n;++i){
while(!dq.empty()&&dq.front()<i-m) dq.pop_front();
if(dq.empty()) ans=max(ans,s[i]);
else ans=max(ans, s[i]-s[dq.front()]); //对头就是最小的s[k]
while(!dq.empty()&&s[dq.back()]>=s[i]) dq.pop_back(); //队尾大于s[i],去尾
dq.push_back(i);
}
cout<<ans<<'\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
solve();
return 0;
}
#include <bits/stdc++.h>
using namespace std;
const int N=2e6+10;
deque<int>dq;
int a[N];
void solve(){
int n,m;cin>>n>>m;
for(int i=1;i<=n;++i) cin>>a[i];
for(int i=1;i<=n;++i){
if(i==1){
cout<<0<<'\n';
dq.push_back(1);
continue;
}
cout<<a[dq.front()]<<'\n';
while(!dq.empty()&&a[i]<=a[dq.back()]) dq.pop_back();
while(!dq.empty()&&i-1-m+1>=dq.front()) dq.pop_front();
dq.push_back(i);
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
solve();
return 0;
}