栈与队列小结
一、理论基础
1.队列是先进先出,栈是先进后出

2.栈和队列是STL(C++标准库)里面的两个数据结构。栈提供push和pop等等接口,所有元素必须符合先进后出规则,所以栈不提供走访功能,也不提供迭代器。
3.栈是以底层容器完成所有的工作,对外提供统一的接口,所以STL往往不被归类为容器,而被归类为container adpter(容器适配器)
4.我们常用的SGI STL,如果没有指定底层实现的话,默认是以deque为缺省情况下栈的底层结构。deque是一个双向队列,只要封住其中一段,只开通另一端就可以实现栈的逻辑
5.SGI STL中队列实现底层实现缺省情况下一样使用deque实现的
std::stack<int, std::vector<int> > third; // 使用vector为底层容器的栈
std::queue<int, std::list<int>> third; // 定义以list为底层容器的队列所以STL队列也不被归类为容器,也是容器适配器
二、力扣题目
1、使用栈实现队列的下列操作:
push(x) 将一个元素放入队列的尾部
pop() 从队列首部移除元素
peek() 返回队列首部的元素
empty() 返回队列是否为空
MyQueue queue = new MyQueue();
queue.push(1);
queue.push(2);
queue.peek(); // 返回 1
queue.pop(); // 返回 1
queue.empty(); // 返回 false说明:
你只能使用标准的栈操作 -- 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)。
思路:
使用栈模拟队列的行为,如果禁用一个栈是不行的,所以需要两个栈一个输入栈,一个输出栈
如果进栈和出栈都为空,说明模拟的队列为空了
class MyQueue {
public:stack<int> stIn;stack<int> stOut;/** Initialize your data structure here. */MyQueue() {}/** Push element x to the back of queue. */void push(int x) {stIn.push(x);}/** Removes the element from in front of queue and returns that element. */int pop() {// 只有当stOut为空的时候,再从stIn里导入数据(导入stIn全部数据)if (stOut.empty()) {// 从stIn导入数据直到stIn为空while(!stIn.empty()) {stOut.push(stIn.top());stIn.pop();}}int result = stOut.top();stOut.pop();return result;}/** Get the front element. */int peek() {int res = this->pop(); // 直接使用已有的pop函数stOut.push(res); // 因为pop函数弹出了元素res,所以再添加回去return res;}/** Returns whether the queue is empty. */bool empty() {return stIn.empty() && stOut.empty();}
};
2、用队列实现栈
使用队列实现栈的下列操作:
push(x) 元素入栈
pop() 移除栈顶元素 (没有返回值)
top() 获取栈顶元素
empty() 返回栈是否为空
front() 返回队头元素 (可以接收返回值!)
back() 返回队尾元素
思路:
用两个队列que1和que2实现队列的功能,que2其实完全就是一个备份的作用,把que1最后面的元素以外的元素都备份到que2,然后弹出最后面的元素,再把其他元素从que2倒回到que1
class MyStack {
public:queue<int> que1;queue<int> que2; // 辅助队列,用来备份/** Initialize your data structure here. */MyStack() {}/** Push element x onto stack. */void push(int x) {que1.push(x);}/** Removes the element on top of the stack and returns that element. */int pop() {int size = que1.size();size--;while (size--) { // 将que1 导入que2,但要留下最后一个元素que2.push(que1.front());que1.pop();}int result = que1.front(); // 留下的最后一个元素就是要返回的值que1.pop();que1 = que2; // 再将que2赋值给que1while (!que2.empty()) { // 清空que2que2.pop();}return result;}/** Get the top element. */int top() {return que1.back();}/** Returns whether the stack is empty. */bool empty() {return que1.empty();}
};3、有效的括号
题目:给定一个只包括'(',')','{','}','[',']' 的字符串,判断字符串是否有效
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
思路:
第一种情况:已经遍历完了字符串,但是栈不为空,说明有相应的左括号没有右括号,所以return false
第二种情况:遍历字符串匹配的过程中,发现栈里没有要匹配的字符了
第三种情况:遍历字符串匹配的过程中,栈已经为空了,没有匹配的字符了,说明右括号没有找到对应的左括号return false
当字符串遍历完之后,栈是空的,就说明全都匹配了
技巧:在匹配左括号的时候,右括号先入栈,就只需要比较当前元素和栈顶是否相等,比左括号先入栈代码实现简单的多
class Solution {
public:bool isValid(string s) {if (s.size() % 2 != 0) return false; // 如果s的长度为奇数,一定不符合要求stack<char> st;for (int i = 0; i < s.size(); i++) {if (s[i] == '(') st.push(')');else if (s[i] == '{') st.push('}');else if (s[i] == '[') st.push(']');// 第三种情况:遍历字符串匹配的过程中,栈已经为空了,没有匹配的字符了,说明右括号没有找到对应的左括号 return false// 第二种情况:遍历字符串匹配的过程中,发现栈里没有我们要匹配的字符。所以return falseelse if (st.empty() || st.top() != s[i]) return false;else st.pop(); // st.top() 与 s[i]相等,栈弹出元素}// 第一种情况:此时我们已经遍历完了字符串,但是栈不为空,说明有相应的左括号没有右括号来匹配,所以return false,否则就return truereturn st.empty();}
};4、删除字符串中的所有相邻重复项
给出由小写字母组成的字符串S,重复项删除操作会选择两个相邻且相同的字母,并删除他们。
在S上反复执行删除操作,直到无法删除,在完成所有重复项删除操作后返回最终的字符串
示例:
输入:"abbaca"
输出:"ca"
解释:例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"。
思路:用栈来存放遍历过的元素,当遍历当前的这个元素的时候,去栈里面看一下我们是不是遍历过相同数值的相邻元素,如果相同,则弹出元素,当栈为空或者元素不相同,则将此元素压入栈中,最后再将栈中元素放到result字符串汇总输出
class Solution {
public:string removeDuplicates(string S) {stack<char> st;for (char s : S) {if (st.empty() || s != st.top()) { //栈为空或者元素不相等st.push(s);} else {st.pop(); // s 与 st.top()相等的情况}}string result = "";while (!st.empty()) { // 将栈中元素放到result字符串汇总result += st.top();st.pop();//别忘了弹出栈顶的元素}reverse (result.begin(), result.end()); //因为从栈中弹出的元素是倒序的 此时字符串需要反转一下return result;}
};5、逆波兰表达式求值
逆波兰表达式:是一种后缀表达式,所谓后缀就是指运算符写在后面,平常所使用表达式是中缀表达式
给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式,请你计算该表达式。返回一个表示表达式值的整数。
注意:
有效的算符为 '+'、'-'、'*' 和 '/' 。
每个操作数(运算对象)都可以是一个整数或者另一个表达式。
两个整数之间的除法总是 向零截断 。
表达式中不含除零运算。
输入是一个根据逆波兰表示法表示的算术表达式。
答案及所有中间计算结果可以用 32 位 整数表示。
示例 1:
输入:tokens = ["2","1","+","3","*"] 输出:9 解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
特点:
去掉括号后表达式无歧义
适合用栈操作运算,遇到数字则入栈;遇到运算符则取出栈顶两个数字进行运算,并将结果压入栈中
思路:逆波兰表达式相当于二叉树中的后序遍历,大家可以把运算符当作中间节点,按照后序遍历左右中的顺序
如果数组中元素检测到是运算符时,此时要先找到需要运算的两个数字元素,且这两个数字相邻且位于栈顶,取出两个数字进行运算
class Solution {
public:int evalRPN(vector<string>& tokens) {// 力扣修改了后台测试数据,需要用longlongstack<long long> st; for (int i = 0; i < tokens.size(); i++) {if (tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/") {long long num1 = st.top();st.pop();long long num2 = st.top();st.pop();if (tokens[i] == "+") st.push(num2 + num1);if (tokens[i] == "-") st.push(num2 - num1);if (tokens[i] == "*") st.push(num2 * num1);if (tokens[i] == "/") st.push(num2 / num1);} else {st.push(stoll(tokens[i]));//检测到是数字则压入栈中}}int result = st.top(); //因为栈中只剩最后一个元素st.pop(); // 把栈里最后一个元素弹出(其实不弹出也没事)return result;}
};其中stoll()函数是将字符串强制转换成long long int型
6、滑动窗口最大值
题目:给定一个数组nums,有一个大小为k的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到滑动窗口的k个数字。滑动窗口每次只向右移动一位,返回滑动窗口的最大值
class Solution {
private:class MyQueue { //单调队列(从大到小)public:deque<int> que; // 使用deque来实现单调队列// 每次弹出的时候,比较当前要弹出的数值是否等于队列出口元素的数值,如果相等则弹出。// 同时pop之前判断队列当前是否为空。void pop(int value) {if (!que.empty() && value == que.front()) {que.pop_front();}}// 如果push的数值大于入口元素的数值,那么就将队列后端的数值弹出,直到push的数值小于等于队列入口元素的数值为止。// 这样就保持了队列里的数值是单调从大到小的了。void push(int value) {while (!que.empty() && value > que.back()) {que.pop_back();}que.push_back(value);}// 查询当前队列里的最大值 直接返回队列前端也就是front就可以了。int front() {return que.front();}};
public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {MyQueue que;vector<int> result;for (int i = 0; i < k; i++) { // 先将前k的元素放进队列que.push(nums[i]);}result.push_back(que.front()); // result 记录前k的元素的最大值for (int i = k; i < nums.size(); i++) {que.pop(nums[i - k]); // 滑动窗口移除最前面元素que.push(nums[i]); // 滑动窗口前加入最后面的元素result.push_back(que.front()); // 记录对应的最大值}return result;}
};
相关文章:
栈与队列小结
一、理论基础1.队列是先进先出,栈是先进后出2.栈和队列是STL(C标准库)里面的两个数据结构。栈提供push和pop等等接口,所有元素必须符合先进后出规则,所以栈不提供走访功能,也不提供迭代器。3.栈是以底层容器…...
SpringBoot整合(五)HikariCP、Druid数据库连接池—多数据源配置
在项目中,数据库连接池基本是必不可少的组件。在目前数据库连接池的选型中,主要是 Druid ,为监控而生的数据库连接池。HikariCP ,号称性能最好的数据库连接池。 在Spring Boot 2.X 版本,默认采用 HikariCP 连接池。而…...
ShardingSphere水平、垂直分库、分表和公共表
目录一、ShardingSphere简介二、ShardingSphere-分库分表1、垂直拆分(1)垂直分库(2)垂直分表2、水平拆分(1)水平分库(2)水平分表三、水平分库操作1、创建数据库和表2、配置分片的规则…...
《分布式技术原理与算法解析》学习笔记Day24
分布式缓存 在计算机领域,缓存是一个非常重要的、用来提升性能的技术。 什么是分布式缓存? 缓存技术是指用一个更快的存储设备存储一些经常用到的数据,供用户快速访问。 分布式缓存是指在分布式环境或者系统下,把一些热门数据…...
强化学习RL 02: Value-based Reinforcement Learning
DQN和TD更新算法。 目录 Review 1. Deep Q-Network(DQN) 1.1 Approximate the Q*(s,a) Function 1.2 Apply DQN to Play Game 1.3 Temporal Difference(TD) Learning 1.4 TD Learning for DQN 1.4.1 TD使用条件 condition 1.4.2 Train DQN using TD learning 1.5 summ…...
08_MySQL聚合函数
1. 聚合函数介绍什么是聚合函数聚合函数作用于一组数据,并对一组数据返回一个值。聚合函数类型AVG()SUM()MAX()MIN()COUNT()注意:聚合函数不能嵌套调用。比如不能出现类似“AVG(SUM(字段名称))”形式的调用。1.1 AVG和SUM函数可以对数值型数据使用AVG 和…...
「TCG 规范解读」词汇表
可信计算组织(Ttrusted Computing Group,TCG)是一个非盈利的工业标准组织,它的宗旨是加强在相异计算机平台上的计算环境的安全性。TCG于2003年春成立,并采纳了由可信计算平台联盟(the Trusted Computing Platform Alli…...
第三阶段-03MyBatis 中使用XML映射文件详解
MyBatis 中使用XML映射文件 什么是XML映射 使用注解的映射SQL的问题: 长SQL需要折行,不方便维护动态SQL查询拼接复杂源代码中的SQL,不方便与DBA协作 MyBatis建议使用XML文件映射SQL才能最大化发挥MySQL的功能 统一管理SQL, 方…...
从0开始学python -41
Python3 命名空间和作用域 命名空间 先看看官方文档的一段话: A namespace is a mapping from names to objects.Most namespaces are currently implemented as Python dictionaries。 命名空间(Namespace)是从名称到对象的映射,大部分的命名空间都是…...
如何将Google浏览器安装到D盘(内含教学视频)
如何将Google浏览器安装到D盘(内含教学视频) 教学视频下载链接地址:https://download.csdn.net/download/weixin_46411355/87503968 目录如何将Google浏览器安装到D盘(内含教学视频)教学视频下载链接地址:…...
三战阿里测试岗,成功上岸,面试才是测试员涨薪真正的拦路虎...
第一次面试阿里记得是挂在技术面上,当时也是技术不扎实,准备的不充分,面试官出的面试题确实把我问的一头雾水,还没结束我就已经知道我挂了这次面试。 第二次面试,我准备的特别充分,提前刷了半个月的面试题…...
Java代码弱点与修复之——ORM persistence error(对象关系映射持久错误)
弱点描述 ORM persistence error, ORM 持久化错误 。表示 ORM 工具在尝试将对象保存到数据库中时出现了问题。可能的原因包括: 数据库连接错误:ORM 工具无法连接到数据库,或者连接到数据库的权限不足。数据库表结构错误:ORM 工具无法正确映射对象和数据库表之间的关系,可…...
原始GAN-pytorch-生成MNIST数据集(原理)
文章目录1. GAN 《Generative Adversarial Nets》1.1 相关概念1.2 公式理解1.3 图片理解1.4 熵、交叉熵、KL散度、JS散度1.5 其他相关(正在补充!)1. GAN 《Generative Adversarial Nets》 Ian J. Goodfellow, Jean Pouget-Abadie, Yoshua Be…...
Vue下载安装步骤的详细教程(亲测有效) 1
目录 一、【准备工作】nodejs下载安装(npm环境) 1 下载安装nodejs 2 查看环境变量是否添加成功 3、验证是否安装成功 4、修改模块下载位置 (1)查看npm默认存放位置 (2)在 nodejs 安装目录下,创建 “node_global…...
[Android Studio] Android Studio生成数字证书,为应用签名
🟧🟨🟩🟦🟪 Android Debug🟧🟨🟩🟦🟪 Topic 发布安卓学习过程中遇到问题解决过程,希望我的解决方案可以对小伙伴们有帮助。 📋笔记目…...
应用IC 卡继续教育网络管理系统前后影响因素比较
3.1 实现了继续护理教育网络化管理近年来,随着一些医院继续护理教育管理信息系统的建立,有效改进了学分档案管理模式和教学模式,但这些继续护理教育管理信息系统一般为局域网,仅能达到满足自身管理的基本需求,而系统如…...
Clickhouse学习(一):MergeTree概述
MergeTree一、Clickhouse表引擎概述二、MergeTree表引擎<一>、ReplacingMergeTree引擎<二>、SummingMergeTree引擎<三>、AggregatingMergeTree引擎三、MergeTree分区一、Clickhouse表引擎概述 MergeTree表引擎:允许根据日期和主键创建索引 1、ReplacingMerge…...
Windows离线安装rust
目前rust安装常用的方式就是通过Rustup安装,此安装方式需要访问互联网。在生产环境中由于网络限制,不能直接访问互联网或者不能访问目标网站,这时候需要用离线安装的方式,本文将详细介绍离线安装步骤,并给出了vscode如…...
Android与flutter混合开发
这里我使用的android studio版本是2020.3.1;flutter版本2.5.3。此前在网上搜索的很多教教程版本都不一样,新版的IDE和SDK让我遇到了很多坑故这里整理一下。一、创建项目1.在Android项目中点击File->New->New Flutter Project。File->New->Ne…...
Linux和C语言的学习方法你真的知道吗?
★Linux的使用 第一天,就给我们讲了为什么要先学c、学linux:因为嵌入式的根本就是软件驱动硬件,而C语言是最接近硬件的语言、有指针的概念、可以直接操作硬件,另外,功能复杂的硬件是含有操作系统的,这就需…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
面向无人机海岸带生态系统监测的语义分割基准数据集
描述:海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而,目前该领域仍面临一个挑战,即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...
群晖NAS如何在虚拟机创建飞牛NAS
套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的----NTFS源代码分析--重要
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的 第一部分: 0: kd> g Breakpoint 9 hit Ntfs!ReadIndexBuffer: f7173886 55 push ebp 0: kd> kc # 00 Ntfs!ReadIndexBuffer 01 Ntfs!FindFirstIndexEntry 02 Ntfs!NtfsUpda…...
前端高频面试题2:浏览器/计算机网络
本专栏相关链接 前端高频面试题1:HTML/CSS 前端高频面试题2:浏览器/计算机网络 前端高频面试题3:JavaScript 1.什么是强缓存、协商缓存? 强缓存: 当浏览器请求资源时,首先检查本地缓存是否命中。如果命…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现指南针功能
指南针功能是许多位置服务应用的基础功能之一。下面我将详细介绍如何在HarmonyOS 5中使用DevEco Studio实现指南针功能。 1. 开发环境准备 确保已安装DevEco Studio 3.1或更高版本确保项目使用的是HarmonyOS 5.0 SDK在项目的module.json5中配置必要的权限 2. 权限配置 在mo…...
Monorepo架构: Nx Cloud 扩展能力与缓存加速
借助 Nx Cloud 实现项目协同与加速构建 1 ) 缓存工作原理分析 在了解了本地缓存和远程缓存之后,我们来探究缓存是如何工作的。以计算文件的哈希串为例,若后续运行任务时文件哈希串未变,系统会直接使用对应的输出和制品文件。 2 …...
2.3 物理层设备
在这个视频中,我们要学习工作在物理层的两种网络设备,分别是中继器和集线器。首先来看中继器。在计算机网络中两个节点之间,需要通过物理传输媒体或者说物理传输介质进行连接。像同轴电缆、双绞线就是典型的传输介质,假设A节点要给…...
内窥镜检查中基于提示的息肉分割|文献速递-深度学习医疗AI最新文献
Title 题目 Prompt-based polyp segmentation during endoscopy 内窥镜检查中基于提示的息肉分割 01 文献速递介绍 以下是对这段英文内容的中文翻译: ### 胃肠道癌症的发病率呈上升趋势,且有年轻化倾向(Bray等人,2018&#x…...
