首页 > 编程语言 >算法竞赛第一章-队列

算法竞赛第一章-队列

时间:2024-05-07 23:16:11浏览次数:17  
标签:head return 队列 第一章 int 算法 rear dq

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

  1. queue <Type>q:定义队列,Type为数据类型,如int、float、char等
  2. q.push(item):把item放进队列
  3. q.front():返回队首元素,但不会删除
  4. q.pop():删除队首元素
  5. q.back():返回队尾元素
  6. q.size():返回元素个数
  7. q.empty():检查队列是否为空

P1540 [NOIP2010 提高组] 机器翻译

#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、单调队列

单调队列解决有长度限制的最大子段和问题
image
image

#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;
}

P1440 求m区间内的最小值传送门

#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;
}

标签:head,return,队列,第一章,int,算法,rear,dq
From: https://www.cnblogs.com/cxy8/p/18167924

相关文章

  • 常见的排序算法——归并排序(二)
    本文记述了自底向上归并排序的基本思想和一份参考实现代码,并在说明了算法的性能后用随机数据进行了验证。◆思想使用自底向上的递推思想进行排序。从大小为1的子范围开始两两归并,得到小规模排序的结果。逐步将子范围的大小翻倍并继续两两归并,直到整个数组范围都已被归并,即得......
  • leedcode-分发饼干(贪心算法)
    自己写的,没有使用排序,会超出时间限制:classSolution:deffindContentChildren(self,g:List[int],s:List[int])->int:iflen(s)==0:return0count=0foriinrange(len(g)):mydict={}forjin......
  • 深入剖析:如何使用Pulsar和Arthas高效排查消息队列延迟问题
    背景前两天收到业务反馈有一个topic的分区消息堆积了:根据之前的经验来看,要么是业务消费逻辑出现问题导致消费过慢,当然也有小概率是消息队列的Bug(我们使用的是pulsar)。排查通过排查,发现确实是在一点多的时候消息堆积了(后面是修复之后堆积开始下降)。于是我在刚才堆积处查......
  • 算法学习笔记(16):Link Cut Tree
    LinkCutTree简称LCT(不是LiChaoTree),是一种非常强大的数据结构。声明该博客写来很大部分目的是帮助自己理解,笔者水平有限,没办法完全原创,有很多内容源自于OI-wiki,和网上博客,见谅。功能考虑一些问题:树上单点查,树上路径修改,这是树上差分可以解决的。那么如果路径查,......
  • 队列的实现
    /********************************************************************************************************** filename: Zqh_队列实现.c* author : [email protected]* date : 2024/05/05* function: 实现队列的增删改查* note : 模板* *Copyright(c)......
  • 以数组为基础实现循环队列
    /*****************************************************************name;CirQueue_Create*function:创建循环队列*parameter;unsighedintsize*ReValue;CirQueue_t**author;小北blog*attention;*date;2024.04.26*history;*version;*Copyright(c)......
  • 二叉树进阶:二叉搜索树、平衡二叉树、KD树(实现KNN算法的快速寻找k个邻居)
    二叉搜索树二叉搜索树又称为二叉排序树、二叉查找树。请记住,本篇所介绍的所有树,都是二叉搜索树,也就是说都用到了二分查找的思想。二叉搜索树的特征:每个结点的左结点都小于结点本身,右结点都大于结点本身。用中序遍历来遍历一棵二叉搜索树,结果必然是有序的。时间复杂度很低......
  • 第一章 Java基础语法
    1-1环境搭建+入门   ......
  • 高一下三调|ssy的队列|hash dp|题解
    SSY的队列题目链接解析:考场上看到这个题第一眼是绝望的,毕竟数论咱是一窍不通.但是往下细看了看这个数据范围,N是很小的,就想了想模拟.然而只骗到10分.这个题绩效较高的解法是状压dp,在N<15的范围之内均可薄纱(ppllxx_9G也是成功拿到这70rank1了orz),可得70,但是一到后......
  • 洛谷P1576最小花费(逆Dijkstra算法)
    背景:说实话,这题有点考建模思想,及对Dijkstra算法的理解思路:因为转账间有手续费,即有一定损失比例,故边权均小于1(比例来说),而边的路权值非和,而是积,故边权相当于负(因为每次乘会使dis[i]变小)而题目刚好求最大路,而边权又等价于全为负,不刚好是Dijkstra的逆运用吗?原理:等......