C++优选算法十二 栈

在C++中,stack 是一种标准模板库(STL)容器适配器,它提供了后进先出(LIFO, Last In First Out)的数据结构。stack 适配器基于其他底层容器(如 deque 或 vector)来实现,但只提供有限的接口来访问这些容器中的元素。

基本用法

包含头文件

要使用 stack,首先需要包含相应的头文件:

#include <stack>
声明一个栈

可以声明一个栈来存储特定类型的元素,例如整数:

std::stack<int> myStack;

默认情况下,stack 使用 std::deque 作为其底层容器。如果需要指定其他底层容器,可以使用模板参数:

std::stack<int, std::vector<int>> myStackWithVector;
常用成员函数
  • push(const T& value):将元素压入栈顶。
  • pop():移除栈顶元素。
  • top():返回栈顶元素的引用,但不移除它。
  • empty():检查栈是否为空,返回布尔值。
  • size():返回栈中元素的个数。
示例代码

以下是一个简单的示例,演示如何使用 stack

#include <iostream>
#include <stack>
int main() {
std::stack<int> myStack;
// 压入元素
myStack.push(10);
myStack.push(20);
myStack.push(30);
// 查看栈顶元素
std::cout << "Top element: " << myStack.top() << std::endl; // 输出 30
// 弹出栈顶元素
myStack.pop();
std::cout << "Top element after pop: " << myStack.top() << std::endl; // 输出 20
// 检查栈是否为空
if (!myStack.empty()) {
std::cout << "Stack is not empty." << std::endl;
}
// 获取栈的大小
std::cout << "Stack size: " << myStack.size() << std::endl; // 输出 2
return 0;
}

注意事项

  1. 访问元素stack 只允许访问栈顶元素,无法直接访问栈中的其他元素。
  2. 性能stack 的性能通常取决于其底层容器的性能。默认情况下,使用 deque 作为底层容器时,push 和 pop 操作的时间复杂度都是 O(1)。
  3. 异常安全性stack 的成员函数在异常发生时能够保持容器的一致性。

总结

stack 是一种非常有用的数据结构,适用于需要后进先出访问模式的场景。通过 C++ STL 提供的 stack 适配器,可以方便地实现这种数据结构,并享受其高效的性能和异常安全性。

示例代码 

1.删除字符串中的所有相邻重复项

给出由小写字母组成的字符串 s重复项删除操作会选择两个相邻且相同的字母,并删除它们。

在 s 上反复执行重复项删除操作,直到无法继续删除。

在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。

示例:

输入:"abbaca"
输出:"ca"
解释:
例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"。

解法(栈)
算法思路:

本题极像我们玩过的「开心消消乐」游戏,当前元素是否被消除,需要知道上一个元素的信息,因此可以用「栈」来保存信息。
但是,如果使用 stack 来保存的话,最后还需要把结果从栈中取出来。不如直接用「数组模拟一个栈」结构:在数组的尾部「尾插尾删」,实现栈的「进栈」和「出栈」。那么最后数组存留的内容就是最后的结果。

重点:能不能想到用栈来解决问题

class Solution {
public:string removeDuplicates(string s){string str;//搞一个数组,模拟栈结构即可int i = 0;while (i < s.size()){if (str.empty()){str += s[i++];continue;}if (s[i] == str.back()){str.pop_back();//出栈i++;}elsestr += s[i++];//进栈}return str;}
};
 2.比较含退格的字符串

给定 s 和 t 两个字符串,当它们分别被输入到空白的文本编辑器后,如果两者相等,返回 true 。# 代表退格字符。

注意:如果对空文本输入退格字符,文本继续为空。

示例 1:

输入:s = "ab#c", t = "ad#c"
输出:true
解释:s 和 t 都会变成 "ac"。

示例 2:

输入:s = "ab##", t = "c#d#"
输出:true
解释:s 和 t 都会变成 ""。

示例 3:

输入:s = "a#c", t = "b"
输出:false
解释:s 会变成 "c",但 t 仍然是 "b"。

解法(用数组模拟栈)
算法思路:

由于退格的时候需要知道「前面元素」的信息,而且退格也符合后进先出」的特性。因此我们可以使用「栈」结构来模拟退格的过程。

  • 当遇到非 #字符的时候,直接进栈;
  • 当遇到 #的时候,栈顶元素出栈。

为了方便统计结果,我们使用「数组」来模拟实现栈结构。 

class Solution {
public:bool backspaceCompare(string s, string t) {string str;string ttr;for(auto x:s){if(x=='#'){if(str.size())str.pop_back();elsecontinue;}elsestr+=x;}for(auto x:t){if(x=='#'){if(ttr.size())ttr.pop_back();elsecontinue;}elsettr+=x;}return str==ttr;}
};
3.基本计算器 II

给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。

整数除法仅保留整数部分。

你可以假设给定的表达式总是有效的。所有中间结果将在 [-231, 231 - 1] 的范围内。

注意:不允许使用任何将字符串作为数学表达式计算的内置函数,比如 eval() 。

示例 1:

输入:s = "3+2*2"
输出:7

示例 2:

输入:s = " 3/2 "
输出:1

示例 3:

输入:s = " 3+5 / 2 "
输出:5

解法(栈)
算法思路:

由于表达式里面没有括号,因此我们只用处理「加减乘除」混合运算即可。根据四则运算的顺序,我们可以先计算乘除法,然后再计算加减法。由此,我们可以得出下面的结论:

  • 当一个数前面是 '+' 号的时候,这一个数是否会被立即计算是「不确定人的,因此我们可以先压入栈中;
  • 当一个数前面是 '-' 号的时候,这一个数是否被立即计算也是「不确定」的,但是这个数已经和前面 的-号绑定了,因此我们可以将这个数的相反数压入栈中;
  • 当一个数前面是 '*' 号的时候,这一个数可以立即与前面的一个数相乘,此时我们让将栈顶的元素乘上这个数;
  • 当一个数前面是 '/' 号的时候,这一个数也是可以立即被计算的,因此我们让栈顶元素除以这个数。

当遍历完全部的表达式的时候,栈中剩余的「元素之和」就是最终结果。 

class Solution {
public:int calculate(string s){vector<int> vv;char op = '+';int tmp = 0;int i = 0;while (i < s.size()){while(s[i] == ' '){i++;}//遇到操作符更新操作符if (!(0 <= s[i] - '0' &&(s[i]-'0') <= 9))op = s[i++];//消除空格while (s[i] == ' '){i++;}//遇到数字提取数字while (0 <=(s[i]-'0')&&(s[i]-'0')<=9){tmp *= 10;tmp += s[i] - '0';i++;}while (s[i] == ' '){i++;}//分类讨论if (op == '+'){vv.push_back(tmp);}if (op == '-'){vv.push_back(-tmp);}if (op == '*'){int num = vv[vv.size() - 1] * tmp;vv.pop_back();vv.push_back(num);}if (op == '/'){int num = vv[vv.size() - 1] / tmp;vv.pop_back();vv.push_back(num);}tmp = 0;}int sum = 0;for (int x : vv){sum += x;}return sum;}
};
 4.字符串解码

给定一个经过编码的字符串,返回它解码后的字符串。

编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。

你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。

此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。

示例 1:

输入:s = "3[a]2[bc]"
输出:"aaabcbc"

示例 2:

输入:s = "3[a2[c]]"
输出:"accaccacc"

示例 3:

输入:s = "2[abc]3[cd]ef"
输出:"abcabccdcdcdef"

解法(两个栈):
算法思路:

对于 3[ab2[cd]],我们需要先解码内部的,再解码外部(为了方便区分,使用了空格):
3[ab2[cd]]->3[abcd cd]-> abcdcd abcdcd abcdcd在解码 cd 的时候,我们需要保存 3 ab 2 这些元素的信息,并且这些信息使用的顺序是从后往前,正好符合栈的结构,因此我们可以定义两个栈结构,一个用来保存解码前的重复次数 k(左括号前的数字),一个用来保存解码之前字符串的信息(左括号前的字符串信息)。

class Solution {
public:string decodeString(string s) {vector<int> istack;vector<string> sstack;sstack.push_back("");int i=0;while(i<s.size()){        //1.遇到数字,提取放入栈int tmp=0;while(0<=(s[i]-'0')&&(s[i]-'0')<=9){tmp*=10;tmp+=s[i]-'0';i++;}if(tmp)istack.push_back(tmp);//2.到'[',提取字符串if(s[i]=='['){i++;string str;while('a'<=s[i]&&s[i]<='z'){str+=s[i++];}sstack.push_back(str);str.clear();}//3.遇到']',解析,放入字符串if(s[i]==']'){string str;int k=istack[istack.size()-1];istack.pop_back();string ttr=sstack[sstack.size()-1];sstack.pop_back();for(int j=0;j<k;j++){str+=ttr;}sstack[sstack.size()-1]+=str;str.clear();i++;}//4.遇到单独字符串,放到栈顶字符串后面string str;while('a'<=s[i]&&s[i]<='z'){str+=s[i++];}sstack[sstack.size()-1]+=str;str.clear();}return sstack[sstack.size()-1];}
};
 5. 验证栈序列

给定 pushed 和 popped 两个序列,每个序列中的 值都不重复,只有当它们可能是在最初空栈上进行的推入 push 和弹出 pop 操作序列的结果时,返回 true;否则,返回 false 。

示例 1:

输入:pushed = [1,2,3,4,5], popped = [4,5,3,2,1]
输出:true
解释:我们可以按以下顺序执行:
push(1), push(2), push(3), push(4), pop() -> 4,
push(5), pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1

示例 2:

输入:pushed = [1,2,3,4,5], popped = [4,3,5,1,2]
输出:false
解释:1 不能在 2 之前弹出。

解法(栈):
算法思路:

用栈来模拟进出栈的流程。
一直让元素进栈,进栈的同时判断是否需要出栈。当所有元素模拟完毕之后,如果栈中还有元素,那么就是一个非法的序列。否则,就是一个合法的序列。

class Solution {
public:bool validateStackSequences(vector<int>& pushed, vector<int>& popped){int i = 0;vector<int> istack;int j = 0;while (j < pushed.size()){istack.push_back(pushed[j++]);while (istack.size() && istack[istack.size()-1] == popped[i]){istack.pop_back();i++;}}return i == popped.size();}
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/59995.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

找工作就上万码优才,海量技术岗位等你来

已至岁末&#xff0c;不论你将实习&#xff0c;或正在求职&#xff0c;求职平台千千万万&#xff0c;但简历如落叶般无人问津。 是否因未找到理想职位而心生焦虑&#xff1f;别急&#xff0c;万码优才在这里&#xff0c;为你点亮职业之路的明灯&#xff01; 今天给大家推荐一…

⭐SmartControl: Enhancing ControlNet for Handling Rough Visual Conditions

目录 0 Abstract 1 Motivation 2 Related Work 2.1 Text-to-Image Diffusion Model 2.2 Controllable Text-to-Image Generation 2.3 ControlNet 2.4 Control Scale Exploration 3 Method 3.1 Framework 3.2 Control Scale Predictor 3.3 Unaligned Data Constructi…

Vue数据响应式原理

前言 Vue是一个结构的框架,也就是 数据层、视图层、数据-视图层&#xff1b;响应式的原理就是实现当数据更新时&#xff0c;视图层也要相应的更新 响应式实现 基于发布订阅模式和数据劫持实现 1.发布订阅模式&#xff1a;vue使用发布订阅模式来实现数据变动的通知和更新 2…

python函数小练习(三)

main.py import testwhile True:test.kdc_menu()ch int(input("请选择>>"))match ch:case 1:test.show_menu()case 2:test.sale_menu()case 3:test.money_menu()case 4:test.mess_menu()case -1:breakcase _:print("请重新输入")test.py menu {…

vue3 + element-plus 的 upload + axios + django 文件上传并保存

之前在网上搜了好多教程&#xff0c;一直没有找到合适自己的&#xff0c;要么只有前端部分没有后端&#xff0c;要么就是写的不是很明白。所以还得靠自己摸索出来后&#xff0c;来此记录一下整个过程。 其实就是不要用默认的 action&#xff0c;要手动实现上传方式 http-reque…

更改Ubuntu22.04锁屏壁纸

更改Ubuntu22.04锁屏壁纸 sudo apt install gnome-shell-extensions gnome-shell-extension-manager安装Gnome Shell 扩展管理器后&#xff0c;打开“扩展管理器”并使用搜索栏找到“锁屏背景”扩展

SDL打开YUV视频

文章目录 问题1&#xff1a;如何控制帧率&#xff1f;问题2&#xff1a;如何触发退出事件&#xff1f;问题3&#xff1a;如何实时调整视频窗口的大小问题4&#xff1a;YUV如何一次读取一帧的数据&#xff1f; 问题1&#xff1a;如何控制帧率&#xff1f; 单独用一个子线程给主线…

SQL server 中 CROSS APPLY的使用

CROSS APPLY 是 SQL Server 中的一个操作符&#xff0c;用于将一个表表达式&#xff08;如子查询、函数等&#xff09;与外部表进行连接。CROSS APPLY 类似于 INNER JOIN&#xff0c;但它允许你在一个查询中多次引用外部表的行&#xff0c;并且可以动态地生成结果集。 基本语法…

【算法】Floyd多源最短路径算法

目录 一、概念 二、思路 三、代码 一、概念 在前面的学习中&#xff0c;我们已经接触了Dijkstra、Bellman-Ford等单源最短路径算法。但首先我们要知道何为单源最短路径&#xff0c;何为多源最短路径 单源最短路径&#xff1a;从图中选取一点&#xff0c;求这个点到图中其他…

纯C++信号槽使用Demo (sigslot 库使用)

sigslot 库与QT的信号槽一样&#xff0c;通过发送信号&#xff0c;触发槽函数&#xff0c;信号槽不是QT的专利&#xff0c;早在2002年国外的一小哥用C写了sigslot 库&#xff0c;简单易用&#xff1b; 该库的官网&#xff08;喜欢阅读的小伙伴可以仔细研究&#xff09;&#xf…

【路径规划】PID搜索算法PSA求解UAV路径规划

摘要 本文研究了基于PID搜索算法&#xff08;PID Search Algorithm, PSA&#xff09;求解无人机&#xff08;UAV&#xff09;路径规划问题。通过引入PID控制思想来控制路径生成过程&#xff0c;使得无人机可以避开障碍物并在复杂地形中寻找最优路径。实验结果表明&#xff0c;…

【大数据学习 | kafka高级部分】kafka的数据同步和数据均衡

1. 数据同步 通过上图我们发现每个分区的数据都不一样&#xff0c;但是三个分区对外的数据却是一致的 这个时候如果第二个副本宕机了 但是如果是leader副本宕机了会发生什么呢&#xff1f; 2. 数据均衡 在线上程序运行的时候&#xff0c;有的时候因为上面副本的损坏&#xff…

java:使用Multi-Release Jar改造Java 1.7项目增加module-info.class以全面合规Java 9模块化规范

common-java是一个我维护了好多年的一个基础项目,编译目标为Java 1.7 现在整个团队的项目要做Java 9以上的技术迁移准备,就需要对这个在内部各项目中被广泛引用的基础项目进行改造,以适合Java 9的模块化规范。 Automatic-Module-Name Java 9的模块化规范(即Java Platform Mod…

二叉树的前中后序遍历

前序遍历:中左右 中序遍历:左中右 后序遍历:左右中 递归法:三种遍历方式代码结构相似&#xff0c;需要搞清楚三个内容:递归函数的返回值&#xff0c;递归函数传递的参数以及递归函数结束的条件 代码随想录 迭代法:需要用栈实现&#xff0c;前序和后序类似&#xff0c;中序…

如何一步步实现api接入JD平台通过url获取item get商品详情字段信息

以下是一步步实现通过 API 接入京东&#xff08;JD&#xff09;平台并使用 URL 获取商品详情&#xff08;Item Get&#xff09;字段信息的大致步骤&#xff1a; 一、注册成为京东开发者并获取 API 权限 注册开发者账号 访问京东api文档&#xff0c;点击注册按钮&#xff0c;按照…

Ubuntu笔记-auto remove

apt autoremove确实是一个非常有用的命令&#xff0c;它用于自动删除系统中不再需要的依赖包。这些依赖包通常是在安装某些软件时自动安装的附加包&#xff0c;而当这些软件被卸载后&#xff0c;这些依赖包也就失去了作用。 然而&#xff0c;许多博客和用户提醒说 apt autorem…

机器视觉基础—双目相机

机器视觉基础—双目相机与立体视觉 双目相机概念与测量原理 我们多视几何的基础就在于是需要不同的相机拍摄的同一个物体的视场是由重合的区域的。通过下面的这种几何模型的目的是要得到估计物体的长度&#xff0c;或者说是离这个相机的距离。&#xff08;深度信息&#xff09…

C++继承(图文非常详细)

继承的概念 1.什么是继承 1.简单定义 我们来看一下下面这串代码注意其中的两个类father 和 son using namespace std; #include<iostream> class father { public:void definity(){cout << "father" << endl;} protected:int tall 180;int age …

解决PyQt5多线程报错:QThread: Destroyed while thread is still running

在使用PyQt5进行多线程开发时&#xff0c;许多初学者会遇到一个常见的问题&#xff1a;程序在运行时没有任何明显的错误信息&#xff0c;但却在终端中报出QThread: Destroyed while thread is still running的警告。而在PyCharm等IDE中&#xff0c;只会看到Process finished wi…

Python中的数据类(dataclass):简化类的定义与数据管理的全面指南

解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! Python 3.7引入的数据类(dataclass)极大地简化了类的定义,尤其在处理数据管理任务时。数据类自动生成__init__、__repr__等方法,帮助开…