当前位置: 首页 > news >正文

算法训练之栈


♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥

♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥

♥♥♥我们一起努力成为更好的自己~♥♥♥

♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥

♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥

✨✨✨✨✨✨个人主页✨✨✨✨✨✨

        这一篇博客我们来探讨一下有关于栈的算法练习题,准备好了吗~我们发车去探索算法的奥秘啦~🚗🚗🚗🚗🚗🚗

目录

前言😁

删除字符串中所有相邻重复项🙃

比较含退格的字符串😜

基本计算器Ⅱ😀

字符串解码😍

验证栈序列😝


前言😁

        我们先来简单复习一下栈这个数据结构,栈(Stack)是一种后进先出的数据结构,我们可以想象一叠盘子:你通常会把新洗好的盘子放在最上面入栈),而当你需要用一个盘子时,你会从最上面拿走一个(出栈),你无法直接从中间或底部抽出一个盘子,栈的工作原理正是如此。

        话不多说,我们上题~

删除字符串中所有相邻重复项🙃

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

        看这题目有点眼熟,既然要删除重复字符,我们就得记录前面一个字符判断是否重复,这也就使用到我们强大的数据结构——栈。

算法思路栈模拟过程

①创建一个空栈

②遍历字符串,如果栈不为空并且栈顶元素与当前字符相等,那么栈顶元素出栈;否则,当前字符入栈

③栈中剩余字符出栈保存到字符串中

代码实现

//删除字符串中所有相邻重复项
class Solution
{
public:string removeDuplicates(string s){//使用数据结构容器——栈stack<char> st;//遍历字符串for (auto& e : s){//如果栈不为空并且栈顶元素与当前字符相等,那么栈顶元素出栈if (st.size() && e == st.top()){st.pop();}//否则,当前字符入栈(包括空栈的情况)else{st.push(e);}}string ret;//保存返回结果while (!st.empty()){ret += st.top();st.pop();}//逆序字符串就是正确结果reverse(ret.begin(), ret.end());return ret;}
};

顺利通过~不过这里的代码看起来还是有一些繁琐,我们有没有什么办法优化一下,主要在于栈中保存的仅仅是字符,需要进行提取才能得到我们的答案,那我们可以与字符串联系起来~

优化思路:因为要返回的是字符串,我们可以使用字符串来模拟栈工作的过程,字符串最后一个位置也就是我们的栈顶~

代码实现

class Solution
{
public:string removeDuplicates(string s){//字符串模拟栈string st;for (auto& e : s){if (st.size() && st.back() == e){st.pop_back();}else{st += e;}}return st;}
};

顺利通过~

比较含退格的字符串😜

比较含退格的字符串

        这一个题目与第一个题目类似,都是使用栈模拟这个过程,我们这里直接给出优化的算法思路~

算法思路字符串模拟栈实现过程

①根据题目要求,每一个字符串进行相同的变化(封装成一个函数changeS)

②changS函数内部使用字符串模拟栈,当栈不为空并且当前字符为‘#'时,栈顶元素出栈;否则,当前字符不为’#‘就入栈(如果对空文本输入退格字符,文本继续为空)

③判断两个字符串变化后是否相等

代码实现

//比较含退格的字符
class Solution
{
public:bool backspaceCompare(string s, string t){return changeS(s) == changeS(t);}string changeS(string s){string ret;for (auto& e : s){//当栈不为空并且当前字符为‘#'时,栈顶元素出栈if (ret.size() && e == '#'){ret.pop_back();}else if (e != '#')//小写字母入栈{ret.push_back(e);}}return ret;}
};

顺利通过~

基本计算器Ⅱ😀

基本计算器Ⅱ

        题目要求我们实现一个简单的计算器,我们这里给出一个巧妙的算法思路~

算法思路使用栈保存正数或者负数

栈存储中间结果:栈用于存储需要累加的值(正数或负数),乘除运算立即计算并更新栈顶

运算符延迟处理:遇到新运算符时只记录,遇到下一个数字时才应用上一个运算符

处理优先级:通过立即计算乘除运算实现"先乘除后加减"

空格直接跳过

栈中所有数据相加就是计算结果

运算符处理规则

前一个运算符当前数字处理方式
+st.push(val)
-st.push(-val)
*st.top() *= val
/st.top() /= val

代码实现

//基本计算器Ⅱ
class Solution
{
public:int calculate(string s){int n = s.size();char c = '+';//运算符号记录stack<int> st;//栈保存计算结果int i = 0;//记录下标while (i < n){//如果是空格,直接跳过!if (s[i] == ' ')i++;//如果是数字else if (s[i] >= '0' && s[i] <= '9'){//提取数字int val = 0;//保存数据while (s[i] >= '0' && s[i] <= '9'){val = val * 10 + (s[i] - '0');i++;}//判断数字前面的运算符if (c == '+'){st.push(val);}else if (c == '-'){st.push(-val);}else if (c == '*'){st.top() *= val;}else if (c == '/'){st.top() /= val;}}//如果是其他,也就是运算符,更新符号else{c = s[i++];}}//取栈中元素相加,得到运算结果int ret = 0;while (!st.empty()){ret += st.top();st.pop();}//返回结果return ret;}
};

顺利通过~这个题目也可以使用数组模拟栈实现功能,大家感兴趣可以自己试一试~

字符串解码😍

字符串解码

        我们需要根据要求进行字符串解码,好在给出的字符串是没有空格的,并且[ ]也是正确匹配的,我们可以进行分情况讨论处理。

算法思路分情况讨论

双栈结构:使用两个独立栈协同工作

st_int:存储数字(重复次数)

st_str:存储字符串片段,初始化时st_str压入空字符串""作为结果容器

四类字符处理逻辑

  • 数字(0-9):
    连续解析完整数字(如"12"→12),压入st_int

  • 左括号([):
    提取后续连续小写字母(如"[abc"→"abc"),作为新片段压入st_str

  • 小写字母(a-z):
    直接拼接到st_str栈顶字符串末尾

  • 右括号(]):
    弹出st_int栈顶数字nst_str栈顶字符串s,将s重复n次后拼接到新栈顶

嵌套解码机制

遇到[时压入新层级,遇到]时完成当前层级解码:

  • 内层字符串先解码(如3[c]→"ccc")

  • 结果拼接到外层字符串(如"ab"+"ccc"→"abccc")

  • 支持任意深度嵌套(如3[a2[c]]→"accaccacc")

结果生成

  • 最终返回st_str栈顶字符串:

    • 初始空字符串作为基础容器

    • 所有层级解码完成后栈顶即完整结果

    • 时间复杂度O(n),空间复杂度O(解码字符串长度)

代码实现

//字符串解码
class Solution
{
public:string decodeString(string s){stack<int> st_int;//保存数字stack<string> st_str;//保存字符串st_str.push("");//插入空字符串,分别后续变形int i = 0;while (i < s.size()){//分情况讨论//如果是数字,提取数字入数字栈if (s[i] >= '0' && s[i] <= '9'){int tmp = 0;while (s[i] >= '0' && s[i] <= '9'){tmp = 10 * tmp + (s[i] - '0');i++;}st_int.push(tmp);}//如果是[,提取后续字符保存到字符栈else if (s[i] == '['){i++;string tmp;while (s[i] >= 'a' && s[i] <= 'z'){tmp += s[i];i++;}st_str.push(tmp);}//如果是字符,那么加到字符栈栈顶字符串末尾else if (s[i] >= 'a' && s[i] <= 'z'){st_str.top() += s[i];i++;}//如果是],就取数字栈和字符栈栈顶,进行拼接else if (s[i] == ']'){string s = st_str.top();int n = st_int.top();st_int.pop();st_str.pop();for (int j = 0; j < n; j++){st_str.top() += s;//新字符栈拼接重复的字符}i++;}}return st_str.top();//字符栈顶就是需要的结果}
};

顺利通过~

验证栈序列😝

验证栈序列

      我们以前都做过类似的文字题,那么使用代码怎么解决呢?答案是进行模拟就可以了~

算法思路使用栈模拟

模拟核心逻辑:使用栈 st 实时模拟入栈/出栈操作,指针 i 跟踪 popped 序列当前位置,验证其合法性

入栈与即时匹配:遍历 pushed 序列:每个元素立即入栈,入栈后循环检查:当栈非空且栈顶元素等于 popped[i] 时→ 弹出栈顶元素→ i 指针后移(匹配成功)

代码实现

//验证栈序列
class Solution
{
public:bool validateStackSequences(vector<int>& pushed, vector<int>& popped){stack<int> st;int i = 0;//用于遍历出栈序列for (auto& e : pushed)//遍历进栈序列{st.push(e);while (st.size() && st.top() == popped[i]){st.pop();i++;}}//通过判断栈是否为空或者i是否走到末尾判断是否为合法出栈序列return st.empty();//return i==popped.size();}
};

顺利通过~


♥♥♥本篇博客内容结束,期待与各位优秀程序员交流,有什么问题请私信♥♥♥

♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥

✨✨✨✨✨✨个人主页✨✨✨✨✨✨


http://www.dtcms.com/a/321560.html

相关文章:

  • provide 和 inject 最佳实践
  • 多任务实时进度监控系统:基于ABP vNext与SignalR的架构实践
  • [激光原理与应用-175]:测量仪器 - 频谱型 - 拉曼光谱仪的工作原理、内部组成、核心芯片、核心算法
  • 项目一系列-第3章 若依框架入门
  • Java中的方法引用操作符(::)详解与实战应用
  • “A flash of inspiration“, protect us from prompt injection?
  • 实习的收获
  • 【Jmeter】设置线程组运行顺序的方法
  • 安装部署K8S集群环境(实测有效版本)
  • 复杂姿态漏检率↓79%!陌讯多模态算法在安全带穿戴识别的落地实践
  • Node.js Turbo 包入门教程
  • web端-登录页面验证码的实现(springboot+vue前后端分离)超详细
  • (Arxiv-2025) CINEMA:通过基于MLLM的引导实现多主体一致性视频生成
  • 基于Jeecgboot3.8.1的flowable流程审批人与发起人相同设置-前端部分
  • Vue2与Vue3 Hooks对比:写法差异与演进思考
  • 【3d61638 渍韵】001 png pdf odt 5与明天各种号(虚拟文章スミレ数据)
  • PDF处理控件Aspose.PDF教程:使用 C#、Java 和 Python 代码调整 PDF 页面大小
  • 以rabbitmq为例演示podman导出导入镜像文件
  • kafka 为什么需要分区?分区的引入带来了哪些好处
  • Kafka + 时间轮 + 数据库实现延迟队列方案
  • 前端开发:JavaScript(7)—— Web API
  • 机器学习视角下的黄金市场动态:3400美元关口的多因子驱动机制
  • Seata分布式事务环境搭建
  • Access开发右下角浮窗提醒
  • RS485转Profibus网关在QDNA钠离子分析仪与S7-300PLC系统集成中的应用
  • 深入解析K-means聚类:从原理到调优实战
  • 基于STM32F030C8T6单片机实现与CH224Q诱骗芯片的I2C通信和电压输出配置
  • 9:USB摄像头的最后一战(上):MP4音视频合封!
  • 《MySQL索引底层原理:B+树、覆盖索引与最左前缀法则》
  • TF 上架全流程实战,从构建到 TestFlight 分发