栈和队列——相关例题

article/2025/10/15 22:32:48

文章目录

  • 一、栈例题——模拟栈
    • 具体实现
      • 1. 模板
        • 1.1 代码注解
        • 1.2 实现代码
      • 2. STL
        • 2.1 代码注解
        • 2.2 实现代码
  • 二、栈例题——表达式求值
    • 具体实现
      • 1. 实现思路
      • 2. 代码注解
      • 3. 实现代码
  • 三、单调栈例题——单调栈
    • 具体实现
      • 1. 实现思路
      • 2. 实现代码
  • 四、队列例题——模拟队列
    • 具体实现
      • 1. 实现思路
      • 2. 代码注解
      • 3. 实现代码
  • 五、队列例题——滑动窗口
    • 具体实现
      • 1. 实现思路
      • 2. 实现代码

提示:栈和队列相关知识点见数据结构-栈和队列

一、栈例题——模拟栈

题目描述

实现一个栈,栈初始为空,支持四种操作:

  • push x – 向栈顶插入一个数 x。
  • pop – 从栈顶弹出一个数。
  • empty – 判断栈是否为空。
  • query – 查询栈顶元素。

现在要对栈进行 M 个操作,其中的每个操作 3 和操作 4 都要输出相应的结果。

输入格式

第一行包含整数 M,表示操作次数。
接下来 M 行,每行包含一个操作命令,操作命令为 push xpopemptyquery

输出格式

对于每个 emptyquery 操作都要输出一个查询结果,每个结果占一行。
其中,empty 操作的查询结果为 YES 或 NO,query 操作的查询结果为一个整数,表示栈顶元素的值。

数据范围

1 ≤ M ≤ 100000
1 ≤ x ≤ 1e9
所有操作保证合法。

输入样例

10
push 5
query
push 6
pop
query
pop
empty
push 4
query
empty

输出样例

5
5
YES
4
NO

具体实现

1. 模板

1.1 代码注解

  • 用数组模拟栈。
  • 下标从 0 开始或者从 1 开始,依据自身习惯即可。
  • 用 top 表示栈顶所在的索引。初始时,top = -1。表示没有元素。
  • push x :栈顶所在索引往后移动一格,然后放入x。st[++top] = x。
  • pop : top 往前移动一格。top–。
  • empty :top 大于等于 0 栈非空,小于 0 栈空。top == -1 ? “YES” : “NO”
  • query : 返回栈顶元素。st[top]

1.2 实现代码

#include<bits/stdc++.h>
using namespace std;const int N=1e5+5;
int m;
int tt,stk[N];
int main()
{cin>>m; while(m--){string s;cin>>s;if(s=="push"){int x;cin>>x;stk[++tt]=x;}else if(s=="pop"){tt--;}else if(s=="query"){cout<<stk[tt]<<endl;}else if(s=="empty"){if(tt>0) puts("NO");else puts("YES");}}system("pause");return 0;
}

2. STL

2.1 代码注解

  • C++ 库中包含 栈(stack),直接调用其相关函数即可。

2.2 实现代码

#include<bits/stdc++.h>
using namespace std;int m;
stack<int>stk;
int main()
{cin>>m; while(m--){string s;cin>>s;if(s=="push"){int x;cin>>x;stk.push(x);}else if(s=="pop"){stk.pop();}else if(s=="query"){cout<<stk.top()<<endl;}else if(s=="empty"){if(!stk.empty()) puts("NO");else puts("YES");}}system("pause");return 0;
}

二、栈例题——表达式求值

题目描述

给定一个表达式,其中运算符仅包含 +,-,*,/(加 减 乘 整除),可能包含括号,请你求出表达式的最终值。
注意:

  • 数据保证给定的表达式合法。
  • 题目保证符号 - 只作为减号出现,不会作为负号出现,例如,-1+2,(2+2)*(-(1+1)+2) 之类表达式均不会出现。
  • 题目保证表达式中所有数字均为正整数。
  • 题目保证表达式在中间计算过程以及结果中,均不超过 231−1。
  • 题目中的整除是指向 0 取整,也就是说对于大于 0 的结果向下取整,例如 5/3=1,对于小于 0 的结果向上取整,例如 5/(1−4)=−1。
  • C++和Java中的整除默认是向零取整;Python中的整除//默认向下取整,因此Python的eval()函数中的整除也是向下取整,在本题中不能直接使用。

输入格式

共一行,为给定表达式。

输出格式

共一行,为表达式的结果。

数据范围

表达式的长度不超过 1e5。

输入样例

(2+2)*(1+1)

输出样例

8

具体实现

1. 实现思路

  • 样例可转换为如下图所示:
    在这里插入图片描述
  • 从表达式分离出一个个整体。
  • 遇到符号,要按照符号的优先级运算。
  • 如果栈顶是 + ,即将入栈的是 + ,栈顶优先级高,需要先计算,再入栈。
  • 如果栈顶是 + ,即将入栈的是 * ,栈顶优先级低,直接入栈。
  • 如果栈顶是 * ,即将入栈的是 + ,栈顶优先级高,需要先计算,再入栈。
  • 如果栈顶是 * ,即将入栈的是 * ,栈顶优先级高,需要先计算,再入栈。
  • 加上括号,括号是特殊处理的,如果没有遇到右括号,则运算最多只能处理到上一个左括号,例如 2 * (3+4),在加号位置不能先算 2 * 3 ,而是先等待。如果遇上了右括号,则一直运算,直到遇到左括号。

2. 代码注解

  • unordered_map<char, int> pr{{‘+’, 1}, {‘-’, 1}, {‘*’, 2}, {‘/’, 2}} 定义加减乘除四则运算的优先级。
  • isdigit() 是 C++ 中的一个函数,主要用于检查其参数是否为十进制数字字符,若为阿拉伯数字 0~9 ,则返回非 0 值,否则返回 0 。
  • 加法,乘法的顺序无所谓,减法,除法要注意两个数的顺序关系。

3. 实现代码

#include <bits/stdc++.h>
using namespace std;stack<int> num;
stack<char> op;void eval()
{auto b = num.top(); num.pop();auto a = num.top(); num.pop();auto c = op.top(); op.pop();int x;if (c == '+'){x = a + b;}else if (c == '-') {x = a - b;}else if (c == '*') {x = a * b;}else {x = a / b;}num.push(x);
}int main()
{unordered_map<char, int> pr{{'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}};string str;cin >> str;for (int i = 0; i < str.size(); i ++ ){auto c = str[i];if (isdigit(c)){int x = 0, j = i;while (j < str.size() && isdigit(str[j])){x = x * 10 + str[j ++ ] - '0';}i = j - 1;num.push(x);}else if (c == '(') {op.push(c);}else if (c == ')'){while (op.top() != '(') eval();{op.pop();}}else{while (op.size() && op.top() != '(' && pr[op.top()] >= pr[c]) eval();{op.push(c);}}}while (op.size()) {eval();}cout << num.top() << endl;system("pause");return 0;
}

三、单调栈例题——单调栈

题目描述

给定一个长度为 N 的整数数列,输出每个数左边第一个比它小的数,如果不存在则输出 −1。

输入格式

第一行包含整数 N,表示数列长度。
第二行包含 N 个整数,表示整数数列。

输出格式

共一行,包含 N 个整数,其中第 i 个数表示第 i 个数的左边第一个比它小的数,如果不存在则输出 −1。

数据范围

1 ≤ N ≤ 1e5
1 ≤ 数列中元素 ≤ 1e9

输入样例

5
3 4 2 7 5

输出样例

-1 3 -1 2 2

具体实现

1. 实现思路

  • 可以用暴力两个 for 循环。
  • 用单调递增栈,当该元素可以入栈的时候,栈顶元素就是它左侧第一个比它小的元素。

在这里插入图片描述

2. 实现代码

#include <bits/stdc++.h>
using namespace std;const int N = 100010;
int stk[N], tt;
int main()
{int n;cin >> n;while (n -- ){int x;cin >> x;while (tt && stk[tt] >= x) {tt -- ;}if (!tt) {cout << "-1" << " ";}else {cout << stk[tt] << " ";}stk[ ++ tt] = x;}system("pause");return 0;
}

四、队列例题——模拟队列

题目描述

实现一个队列,队列初始为空,支持四种操作:

  • push x – 向队尾插入一个数 x。
  • pop – 从队头弹出一个数。
  • empty – 判断队列是否为空。
  • query – 查询队头元素。

现在要对队列进行 M 个操作,其中的每个操作 3 和操作 4 都要输出相应的结果。

输入格式

第一行包含整数 M,表示操作次数。
接下来 M 行,每行包含一个操作命令,操作命令为 push xpopemptyquery 中的一种。

输出格式

对于每个 emptyquery 操作都要输出一个查询结果,每个结果占一行。
其中,empty 操作的查询结果为 YESNOquery 操作的查询结果为一个整数,表示队头元素的值。

数据范围

1 ≤ M ≤ 100000
1 ≤ x ≤ 1e9
所有操作保证合法。

输入样例

10
push 6
empty
query
pop
empty
push 3
push 4
pop
query
push 6

输出样例

NO
6
YES
4

具体实现

1. 实现思路

  • 用一个数组 q 保存数据。
  • 用 hh 代表队头,q[hh] 就是队头元素, q[hh + 1] 就是第二个元素。
  • 用 tt 代表队尾, q[tt] 就是队尾元素, q[tt + 1] 就是下一次入队,元素应该放的位置。
  • [hh, tt] 左闭右闭,代表队列中元素所在的区间。
  • 出队pop:因为 hh 代表队头,[hh, tt] 代表元素所在区间。所以出队可以用 hh++实现,hh++后,区间变为[hh + 1, tt]。
  • 入队push:因为 tt 代表队尾,[hh, tt] 代表元素所在区间。所以入出队可以用 tt++实现,tt++后,区间变为[hh, tt + 1], 然后在q[tt+1]位置放入入队元素。
  • 是否为空empty:[hh, tt] 代表元素所在区间,当区间非空的时候,对列非空。也就是tt >= hh的时候,对列非空。
  • 询问队头query:用 hh 代表队头,q[hh] 就是队头元素,返回 q[hh] 即可。

在这里插入图片描述

2. 代码注解

  • hh <= tt ? “NO” : “YES” 是三目运算符,如果 hh<=tt ,则输出 NO ,否则输出 YES。

3. 实现代码

#include <bits/stdc++.h>
using namespace std;const int N = 100010;
int m;
int q[N], hh, tt = -1;int main()
{cin >> m;while (m -- ){string op;int x;cin >> op;if (op == "push"){cin >> x;tt++; q[tt] = x;}else if (op == "pop") {hh ++ ;}else if (op == "empty") {cout << (hh <= tt ? "NO" : "YES") << endl;}else {cout << q[hh] << endl;}}system("pause");return 0;
}

五、队列例题——滑动窗口

题目描述

给定一个大小为 n ≤ 1e6 的数组。
有一个大小为 k 的滑动窗口,它从数组的最左边移动到最右边。
你只能在窗口中看到 k 个数字。
每次滑动窗口向右移动一个位置。
以下是一个例子:
该数组为 [1 3 -1 -3 5 3 6 7],k 为 3。

窗口位置最小值最大值
[1 3 -1] -3 5 3 6 7-13
1 [3 -1 -3] 5 3 6 7-33
1 3 [-1 -3 5] 3 6 7-35
1 3 -1 [-3 5 3] 6 7-35
1 3 -1 -3 [5 3 6] 736
1 3 -1 -3 5 [3 6 7]37

你的任务是确定滑动窗口位于每个位置时,窗口中的最大值和最小值。

输入格式

输入包含两行。
第一行包含两个整数 n 和 k,分别代表数组长度和滑动窗口的长度。
第二行有 n 个整数,代表数组的具体数值。
同行数据之间用空格隔开。

输出格式

输出包含两个。
第一行输出,从左至右,每个位置滑动窗口中的最小值。
第二行输出,从左至右,每个位置滑动窗口中的最大值。

输入样例

8 3
1 3 -1 -3 5 3 6 7

输出样例

-1 -3 -3 -3 3 3
3 3 5 5 6 7

具体实现

1. 实现思路

  • 有题目可知,窗口大小为 3 ,因此要先从数组的第一个元素开始,遍历三个元素形成窗口后,再进行判断。
  • 为了保持窗口的大小为3,左侧元素就需要从窗口中剔除。这样使得窗口一直在向右移动,直到考察到最后一个元素结束。
  • 如下图过程:

在这里插入图片描述

  • 以最大值为例:
  • 如果当前的滑动窗口中有两个下标 i 和 j ,其中 i 在 j 的左侧(i<j),并且 i 对应的元素不大于 j 对应的元素(nums[i]≤nums[j]),则:
  • 当滑动窗口向右移动时,只要 i 还在窗口中,那么 j 一定也还在窗口中。这是由于 i 在 j 的左侧所保证的。
  • 因此,由于 nums[j] 的存在,nums[i] 一定不会是滑动窗口中的最大值了,我们可以将nums[i]永久地移除。
  • 因此我们可以使用一个队列存储所有还没有被移除的下标。在队列中,这些下标按照从小到大的顺序被存储,并且它们在数组nums中对应的值是严格单调递减的。
  • 当滑动窗口向右移动时,我们需要把一个新的元素放入队列中。
  • 为了保持队列的性质,我们会不断地将新的元素与队尾的元素相比较,如果新元素大于等于队尾元素,那么队尾的元素就可以被永久地移除,我们将其弹出队列。我们需要不断地进行此项操作,直到队列为空或者新的元素小于队尾的元素。
  • 由于队列中下标对应的元素是严格单调递减的,因此此时队首下标对应的元素就是滑动窗口中的最大值。
  • 窗口向右移动的时候。因此我们还需要不断从队首弹出元素保证队列中的所有元素都是窗口中的,因此当队头元素在窗口的左边的时候,弹出队头。

2. 实现代码

#include <bits/stdc++.h>
using namespace std;const int N = 1000010;
int a[N], q[N];
int main()
{int n, k;cin >> n >> k;for (int i = 0; i < n; i ++ ){cin >> a[i];}int hh = 0, tt = -1;for (int i = 0; i < n; i ++ ){if (hh <= tt && i - k + 1 > q[hh]) {hh ++ ;}while (hh <= tt && a[q[tt]] >= a[i]) {tt -- ;}q[ ++ tt] = i;if (i >= k - 1) {cout << a[q[hh]] << " ";}}puts("");hh = 0, tt = -1;for (int i = 0; i < n; i ++ ){if (hh <= tt && i - k + 1 > q[hh]){hh ++ ;}while (hh <= tt && a[q[tt]] <= a[i]){tt -- ;}q[ ++ tt] = i;if (i >= k - 1) {cout << a[q[hh]] << " ";}}puts("");system("pause");return 0;
}

http://chatgpt.dhexx.cn/article/yGDaNnB1.shtml

相关文章

【栈和队列】

大家好,这里是针对栈和队列做的一些总结归类,主要是介绍了栈和队列的相关操作,特意整理出来一篇博客供我们一起复习和学习,如果文章中有理解不当的地方,还希望朋友们在评论区指出,我们相互学习,共同进步! 文章目录 一&#xff1a;栈1.1 栈的概念及结构1.2 栈的实现1.3 典型案例…

栈、队列

顺序栈&#xff0c;即栈的顺序存储结构是利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素&#xff0c;同时附设指针top指示栈项元素在顺序栈中的位置。通常的习惯做法是以top&#xff1d;0表示空栈&#xff0c;鉴于C语言中数组的下标约定从0开始&#xff0c;则当以C…

栈、队列、数组

栈 定义 #include <stdio.h>/* 栈只允许在栈顶插入删除操作的线性表Last Insert First Out. */// 顺序栈#define MaxSize 10typedef struct {int data[MaxSize]; // 静态数组存放栈元素int top; // 栈顶指针 } SqStack; 栈顶指针指向栈顶元素的栈 空为-1 // 栈顶指针指…

使用SQL进行两个表关联查询(inner)

结果显示 公司类型表 公司表 实现方式 SELECTt_company.id,cName, typeName, cDescribe, t_company.modifyTime, t_company.createTime FROMt_company INNER JOIN t_company_type ON t_company.cType t_company_type.id代码解析 SELECT 显示字段,如果两个表都有字段,则需要…

sql进行两个关联表,根据其中一个表的一个属性进行条件查询查询

我最近遇到了表的查询,但是通过查询发现,网上的sql的大神,写的文章到底是什么玩意? 我打算自己写一个sql专栏,特意讲解sql的使用,来帮助大家 这篇文章技术指导为sql进行两个关联表,根据其中一个表的一个属性进行条件查询查询 假设只有两张表,其中一张表最后一个外键连…

SQL关联查询详解,SQL JOIN详解

关联查询&#xff0c;也称为多表查询&#xff0c;指两个或更多个表一起完成查询操作。 前提条件&#xff1a;这些一起查询的表之间是有关系的&#xff08;一对一、一对多&#xff09;&#xff0c;它们之间一定是有关联字段&#xff0c;这个关联字段可能建立了外键&#xff0c;也…

SQL-多表关联查询详解

为了在工作中能更顺利的使用多表关联查询&#xff0c;今天这篇博客就写这个内容了。 在讲解多表关联查询之前&#xff0c;先生成测试表。 登录scott用户&#xff0c;运行以下语句生成测试表。 create table ex1 as select * from emp; create table ex2 as select * from dept…

Mysql如何对两张表的相同字段,同时查询两张数据表

前言 假设现在有两张数据表 表1如下&#xff1a; 表2如下&#xff1a; 表1和表2同时都再mysql的情况下&#xff0c;只有他们的uuid是一样的&#xff0c;其他字段信息不同&#xff0c;现在需要用sql语句根据uuid&#xff0c;同时将符合要求的数据查询出来&#xff0c;怎么做呢&…

SQL- join多表关联

一、SQL 连接(JOIN) 1、笛卡尔积 &#xff08;1&#xff09;当多张表进行连接查询&#xff0c;没有任何条件限制的时候&#xff0c;最终查询结果条数&#xff0c;是多张表条数的乘积 如A表15条&#xff08;行&#xff09;数据&#xff0c;B表20条&#xff08;行&#xff09;…

SQL语言多表关联查询

新建两张表&#xff1a; 表1&#xff1a;student 截图如下&#xff1a; 表2&#xff1a;course 截图如下&#xff1a; &#xff08;此时这样建表只是为了演示连接SQL语句&#xff0c;当然实际开发中我们不会这样建表&#xff0c;实际开发中这两个表会有自己不同的主键。&…

[转载]静息态fMRI、DTI、VBM

[转载]静息态fMRI、DTI、VBM (2014-06-19 19:00:15) 转载▼ 标签&#xff1a; 转载 分类&#xff1a; fMRI-EEG 原文地址&#xff1a;静息态fMRI、DTI、VBM作者&#xff1a;426l 一、 简介 1、静息态fMRI数据处理学习内容 BOLD-fMRI技术自1990年发明至今&#xff0c;已经成…

用FSL进行VBM统计分析

用FSL进行VBM统计分析 总体步骤概览1.准备数据1.1 T1数据格式1.2 Template_list查看数据 2.剥头皮&#xff1a;fslvbm_1_bet3.数据分割生成模板&#xff1a;fslvbm_2_template4.后处理&#xff08;标准化、调制、平滑&#xff09;&#xff1a;fslvbm_3_proc5.统计检验5.2查看结…

[spm操作] VBM分析中,modulation的作用

本帖作为 《用Matlab和SPM批量处理被试的经验总结》 的一部分 目录贴请见 http://home.52brain.com/forum.ph ... 1&extra#pid158525 在VBM分析中&#xff0c;通常都有一个modulation的选项&#xff0c;有些滴友对这个步骤的作用有点不太理解。 我先举一个例子&#xff…

不同的工具包对Voxel-based morphometry (VBM)计算结果的影响

​《本文同步发布于“脑之说”微信公众号&#xff0c;欢迎搜索关注~~》 前期大量的MRI研究已经表明&#xff0c;精神分裂患者很多脑区的局部灰质体积&#xff08;regional grey matter volume&#xff09;出现异常变化&#xff0c;但是这些研究的结果似乎并不一致。而这种结果…

如何提取差异脑区的灰质体积与临床量表算相关?——基于体素的形态学方法(VBM)

基于体素的形态学方法(VBM)是分析大脑解剖学(结构)差异最常用方法之一, 其通过给大脑volume逐体素打标签(分类)的方式来进行组织分割,过程高度自动化,比传统的基于ROI先验假设的分析方式得到的结果,更加具有稳定性和可重复性。VBM可以定量地测量出脑组织中各组织成分的…

VBM后的双样本t检验

上一篇文章写到做完了VBM&#xff0c;做完后因为数据一般都是患者组和HC组&#xff0c;这两个组之间需要进行比较&#xff0c;那么我们就要进行双样本t检验。 这里介绍双样本t检验的做法。 依然使用的是SPM-fMRI。 1.第一步是选择Specify 2nd-level 打开以后我们可以看到这个界…

VBM后的配对t检验以及xjview使用

之前写了VBM后的双样本t检验&#xff0c;再记录一下配对t检验。 配对t检验和双样本t检验的过程基本一致。包括以下三个步骤。 第一步输入两组被试时&#xff0c;应该成对输入&#xff0c;共有几个被试就有几个pair。 但是这里我在做的过程中没有加协变量&#xff0c;不知道会不…

Visual Basic

目录 一&#xff0c;Visual Basic 二&#xff0c;控制台程序 三&#xff0c;可视化程序 1&#xff0c;IDE 2&#xff0c;实例——加法计算器 一&#xff0c;Visual Basic Visual Basic是可视化的Basic&#xff0c;简称VB VB是第一个可视化编程语言。 二&#xff0c;控制…

VBM法MRI图像处理——记第一次使用cat12

1.环境 MATLAB 2015b SPM12 CAT12 2.SPM部分 命令行输入 spm 出现 以及 点击Toolbox 出现 3.CAT部分 点击上图 设置请根据自己需求 多分割了一种surface皮层数据&#xff0c;当做皮层统计分析SBM时需要提取surface皮层指标时会用到。 我本意只是获得灰质、白质的体积…