栈(典型算法思想)—— OJ例题算法解析思路

目录

一、1047. 删除字符串中的所有相邻重复项 - 力扣(LeetCode)

算法代码: 

1. 初始化结果字符串

2. 遍历输入字符串

3. 检查和处理字符

4. 返回结果

总结

二、844. 比较含退格的字符串 - 力扣(LeetCode) 

算法代码: 

1. 主函数 backspaceCompare

2. 辅助函数 changeStr

3. 遍历输入字符串

4. 处理字符

5. 返回处理结果

6. 返回比较结果

总结

三、227. 基本计算器 II - 力扣(LeetCode) 

算法代码: 

1. 初始化变量

2. 遍历字符串

3. 处理空格

4. 处理数字

5. 处理运算符

6. 计算结果

7. 返回结果

总结

四、394. 字符串解码 - 力扣(LeetCode) 

算法代码: 

1. 初始化栈

2. 遍历输入字符串

3. 处理字符

4. 返回结果

总结

五、946. 验证栈序列 - 力扣(LeetCode) 

算法代码: 

1. 初始化栈

2. 遍历 pushed 序列

3. 检查弹出条件

4. 返回验证结果

总结


一、1047. 删除字符串中的所有相邻重复项 - 力扣(LeetCode)

算法代码: 

class Solution {
public:string removeDuplicates(string s) {string ret; // 搞⼀个数组,模拟栈结构即可for (auto ch : s) {if (ret.size() && ch == ret.back())ret.pop_back(); // 出栈elseret += ch; // ⼊栈}return ret;}
};

1. 初始化结果字符串

  • 结果字符串 ret:用于存储处理后的结果,模拟栈的行为。

2. 遍历输入字符串

  • 字符遍历:使用范围 for 循环逐个访问字符串 s 中的每个字符 ch

3. 检查和处理字符

  • 判断条件

    • 栈不为空:检查 ret 的大小(ret.size()),如果不为零,表示栈中有元素。

    • 相邻字符比较:如果当前字符 ch 与 ret 中的最后一个字符(ret.back())相同,说明发现了相邻的重复字符。

      • 出栈:使用 pop_back() 方法移除 ret 中的最后一个字符,相当于“出栈”操作。

    • 入栈:如果当前字符 ch 不与最后一个字符相同,或者 ret 为空,说明没有重复字符,将该字符追加到 ret 中(ret += ch),相当于“入栈”。

4. 返回结果

  • 最终结果:当所有字符都处理完毕后,ret 中存储的就是移除了所有相邻重复字符的结果,直接返回这个字符串。

总结

        该算法通过模拟栈的结构,有效地处理了相邻的重复字符。时间复杂度为 O(n),其中 n 是字符串 s 的长度,因为每个字符最多只被访问和处理两次(入栈和出栈)。这种方法简单且高效,适合快速移除字符串中的相邻重复字符。

二、844. 比较含退格的字符串 - 力扣(LeetCode) 

算法代码: 

class Solution {
public:bool backspaceCompare(string s, string t) {return changeStr(s) == changeStr(t);}string changeStr(string& s) {string ret; // ⽤数组模拟栈结构for (char ch : s) {if (ch != '#')ret += ch;else {if (ret.size())ret.pop_back();}}return ret;}
};

1. 主函数 backspaceCompare

  • 比较结果:调用 changeStr(s) 和 changeStr(t) 来处理两个字符串,并比较它们是否相等。

2. 辅助函数 changeStr

  • 初始化结果字符串 ret:用于存储处理后的字符串,模拟栈的行为。

3. 遍历输入字符串

  • 字符遍历:使用范围 for 循环逐个访问字符串 s 中的每个字符 ch

4. 处理字符

  • 判断字符

    • 如果当前字符 ch 不是 #,则将其添加到结果字符串 ret 中(ret += ch),表示保留这个字符。

    • 如果当前字符是 #,则:

      • 检查 ret 是否为空(ret.size())。如果不为空,说明可以安全地删除最后一个字符,调用 pop_back() 删除 ret 中的最后一个字符。

5. 返回处理结果

  • 最终结果:当所有字符都处理完毕后,返回处理后的字符串 ret,即字符串 s 在考虑回退字符后得到的结果。

6. 返回比较结果

  • 比较处理后的字符串:在 backspaceCompare 函数中,比较两个处理后的字符串是否相等。

总结

        该算法使用模拟栈的方式有效地处理了字符串中的回退操作。两次遍历字符串 s 和 t,每个字符最多访问和处理一次,因此时间复杂度为 O(n + m),其中 n 和 m 是两个字符串的长度。这种方法简洁且高效,适合在处理带有回退操作的字符串比较时使用。

三、227. 基本计算器 II - 力扣(LeetCode) 

算法代码: 

class Solution {
public:int calculate(string s) {vector<int> st; // ⽤数组来模拟栈结构int i = 0, n = s.size();char op = '+';while (i < n) {if (s[i] == ' ')i++;else if (s[i] >= '0' && s[i] <= '9') {// 先把这个数字给提取出来int tmp = 0;while (i < n && s[i] >= '0' && s[i] <= '9')tmp = tmp * 10 + (s[i++] - '0');if (op == '+')st.push_back(tmp);else if (op == '-')st.push_back(-tmp);else if (op == '*')st.back() *= tmp;elsest.back() /= tmp;} else {op = s[i];i++;}}int ret = 0;for (auto x : st)ret += x;return ret;}
};

1. 初始化变量

  • 栈 st:使用一个 vector<int> 来模拟栈结构,存储操作数。

  • 索引 i:初始化为 0,用于遍历字符串 s

  • 运算符 op:初始化为 '+',表示当前的运算符。

2. 遍历字符串

  • 循环条件:使用 while (i < n) 遍历整个字符串,直到所有字符都被处理完。

3. 处理空格

  • 跳过空格:如果当前字符是空格,直接将索引 i 加一,继续检查下一个字符。

4. 处理数字

  • 提取数字:如果当前字符是数字(在 '0' 到 '9' 之间),使用一个 while 循环来提取完整的数字。通过将 tmp 乘以 10 并加上当前数字的值 (s[i] - '0') 来构建这个数字。

  • 根据运算符处理数字

    • 如果 op 是 '+',将 tmp 添加到栈中。

    • 如果 op 是 '-',将 -tmp 添加到栈中(表示减去这个数)。

    • 如果 op 是 '*',将栈顶元素(最后一个数字)与 tmp 相乘,并更新栈顶元素的值。

    • 如果 op 是 '/',将栈顶元素与 tmp 相除,并更新栈顶元素的值。

5. 处理运算符

  • 更新运算符:如果当前字符是运算符(+-*/),将 op 更新为当前字符,索引 i 加一。

6. 计算结果

  • 求和:遍历栈 st,将所有元素累加到结果变量 ret 中。

7. 返回结果

  • 返回最终结果:返回计算得到的结果 ret

总结

        这个计算器的设计通过使用栈结构有效地处理了四则运算的优先级,特别是乘法和除法的优先级高于加法和减法。时间复杂度为 O(n),其中 n 是字符串的长度,因为每个字符最多只被访问和处理一次。这种方法简洁高效,适合处理没有括号的简单数学表达式的计算。

四、394. 字符串解码 - 力扣(LeetCode) 

算法代码: 

class Solution {
public:string decodeString(string s) {stack<int> nums;stack<string> st;st.push("");int i = 0, n = s.size();while (i < n) {if (s[i] >= '0' && s[i] <= '9') {int tmp = 0;while (s[i] >= '0' && s[i] <= '9') {tmp = tmp * 10 + (s[i] - '0');i++;}nums.push(tmp);} else if (s[i] == '[') {i++; // 把括号后⾯的字符串提取出来string tmp = "";while (s[i] >= 'a' && s[i] <= 'z') {tmp += s[i];i++;}st.push(tmp);} else if (s[i] == ']') {string tmp = st.top();st.pop();int k = nums.top();nums.pop();while (k--) {st.top() += tmp;}i++; // 跳过这个右括号} else {string tmp;while (i < n && s[i] >= 'a' && s[i] <= 'z') {tmp += s[i];i++;}st.top() += tmp;}}return st.top();}
};

1. 初始化栈

  • 数字栈 nums:用于存储括号前的重复次数。

  • 字符串栈 st:用于存储当前构建的字符串。在开始时,将一个空字符串推入栈中。

2. 遍历输入字符串

  • 索引变量 i:用于遍历字符串 s,初始化为 0,n 为字符串的长度。

3. 处理字符

  • 数字处理

    • 如果字符是数字(在 '0' 到 '9' 之间),需要提取完整的数字。使用一个 while 循环来处理可能为多位数的数字,然后将提取出的数字推入 nums 栈中。

  • 左括号处理

    • 如果遇到 '[',说明要开始一个新的重复段。在此之前需要将当前构建的字符串(即 st 栈顶)推入栈中,然后开始从 '[' 后面提取字符串(直到下一个右括号 ']')。

    • 使用 while 循环提取后续的字母字符,直到遇到非字母字符(此时 i 应该指向右括号或下一个数字),将提取出的字符串推入 st 栈中。

  • 右括号处理

    • 当遇到 ']' 时,从 st 栈中弹出字符串(这就是在这个括号内的字符串),并从 nums 栈中弹出数字(这是重复的次数)。

    • 使用一个 while 循环将弹出的字符串重复 k 次,然后将其添加到 st 栈顶的字符串中。

  • 普通字母处理

    • 如果字符是字母(不在数字和括号内),则使用一个 while 循环提取连续的字母,并将其添加到 st 栈顶的字符串中。

4. 返回结果

  • 最终结果:遍历完所有字符后,st 栈顶保存的就是解码后的完整字符串,返回 st.top()

总结

        该算法使用了两个栈来有效地处理字符串的解码。时间复杂度为 O(n),其中 n 是字符串的长度,因为每个字符最多被访问和处理两次。该方法能够简单、清晰地处理包含嵌套结构的字符串解码问题,适合需要解析类似格式的字符串的场景。

五、946. 验证栈序列 - 力扣(LeetCode) 

算法代码: 

class Solution {
public:bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {stack<int> st;int i = 0, n = popped.size();for (auto x : pushed) {st.push(x);while (st.size() && st.top() == popped[i]) {st.pop();i++;}}return i == n;}
};

1. 初始化栈

  • 栈 st:用于模拟栈的行为,记录当前压入的元素。

  • 索引变量 i:初始化为 0,用于跟踪在 popped 中需要弹出的元素的位置。

  • 变量 n:记录 popped 的大小。

2. 遍历 pushed 序列

  • 使用范围 for 循环遍历 pushed 中的每个元素 x,将其压入栈 st

3. 检查弹出条件

  • 在每次压入新元素后,使用一个 while 循环检查栈顶元素是否与 popped[i] 相等:

    • 如果相等,则弹出栈顶元素(st.pop()),并将 i 增加 1,以便检查下一个要弹出的元素。

    • 如果不相等,继续执行压入操作。

4. 返回验证结果

  • 最后,比较 i 和 n 的值:

    • 如果 i 等于 n,说明所有元素都按照 popped 的顺序被成功弹出,返回 true

    • 如果 i 不等于 n,则说明弹出顺序与给定的 popped 不匹配,返回 false

总结

        该算法使用一个栈来模拟压入和弹出的过程,时间复杂度为 O(n),其中 n 是 pushed 和 popped 的长度,因为每个元素最多被压入和弹出一次。该方法简单而高效,非常适合用来验证栈操作的合法性。

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

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

相关文章

Qt中基于开源库QRencode生成二维码(附工程源码链接)

目录 1.QRencode简介 2.编译qrencode 3.在Qt中直接使用QRencode源码 3.1.添加源码 3.2.用字符串生成二维码 3.3.用二进制数据生成二维码 3.4.界面设计 3.5.效果展示 4.注意事项 5.源码下载 1.QRencode简介 QRencode是一个开源的库&#xff0c;专门用于生成二维码&…

字符串哈希动态规划_6

一.字符串哈希 字符串哈希概述 字符串哈希是一种将字符串映射到一个数值的技术&#xff0c;常用于处理字符串相关的算法问题&#xff0c;尤其在处理字符串匹配、子串查找等问题时非常高效。它的核心思想是利用一个哈希函数将字符串映射成一个整数&#xff0c;并根据该整数来判…

Kubernetes控制平面组件:Kubernetes如何使用etcd

云原生学习路线导航页&#xff08;持续更新中&#xff09; kubernetes学习系列快捷链接 Kubernetes架构原则和对象设计&#xff08;一&#xff09;Kubernetes架构原则和对象设计&#xff08;二&#xff09;Kubernetes架构原则和对象设计&#xff08;三&#xff09;Kubernetes控…

Mybatis后端数据库查询多对多查询解决方案

问题场景&#xff1a; 我开发的是一个论文选择系统。 后端用一个论文表paper来存储论文信息。 论文信息中&#xff0c;包含前置课程&#xff0c;也就是你需要修过这些课程才能选择这个论文。 而一个论文对应的课程有很多个。 这样就造成了一个数据库存储的问题。一个paper…

BGP配置华为——RR反射器配置

实验拓扑 与之前实验同理将loop0作为routerID使用&#xff0c;且R1和R2上用loop1接口用于模拟用户其他网段 实验要求 1&#xff0c;在AS100内运行OSPF协议 2.配置路由反射器&#xff0c;使得从R1进入的数据能够反射到全局网络 3.在R1和R2上分别宣告自己的loop1口网段用于观…

CentOS7 离线安装 Postgresql 指南

一、背景 服务器通常都是离线内网环境&#xff0c;想要通过联网方式一键下载安装 Postgresql 不太现实&#xff0c;本文将介绍如何在 CentOS7 离线安装 Postgresql&#xff0c;以及遇到困难如何解决。 二、安装包下载 先在本地下载好 rpm 包&#xff0c;再通过 ftp 上传到服…

vue3项目实践心得-寻找未被使用的最小编号

&#x1f9e1;&#x1f9e1;遇到的问题&#x1f9e1;&#x1f9e1; 在用vue3ts编写编译原理项目中”绘制状态转换图“时&#xff0c;有一个添加状态的功能按钮&#xff0c;用户点击按钮即可添加一个新的状态&#xff0c;至于新的状态的编号值&#xff0c;想着以”最小未被使用…

FPGA简介|结构、组成和应用

Field Programmable Gate Arrays&#xff08;FPGA&#xff0c;现场可编程逻辑门阵列&#xff09;&#xff0c;是在PAL、GAL、CPLD等可编程器件的基础上进一步发展的产物&#xff0c; 是作为专用集成电路&#xff08;ASIC&#xff09;领域中的一种半定制电路而出现的&#xff0c…

C# 入门简介

关于C# ​ C# &#xff08;读作C Sharp&#xff09;是由微软公司开发的一种面向对象、类型安全、高效且简单的编程语言&#xff0c;最初于 2000 年发布&#xff0c;并随后成为 .NET 框架的一部分。所以学习C#语言的同时&#xff0c;也是需要同步学习.NET框架的&#xff0c;不过…

处理使用 mapstruct 导致分页总数丢失问题

问题 PageHelper 分页总数不对&#xff0c;返回的总数老是等于当前页数目 分析 问题出现在 domain 转 VO 这个步骤&#xff0c;当我把数据库实体类型的 list 转为 vo 类型的 list&#xff0c;然后放进 PageInfo 则会丢失分页信息&#xff1b; 解决方式 从数据库查询出来后…

LabVIEW中的icon.llb 库

icon.llb 库位于 C:\Program Files (x86)\National Instruments\LabVIEW 2019\vi.lib\Platform 目录下&#xff0c;是 LabVIEW 系统中的一个重要库。它的主要功能是与图标相关的操作&#xff0c;提供了一些实用的 VI 用于处理 LabVIEW 图标的显示、修改和设置。通过该库&#x…

【ProtoBuf】文件编写及序列化

ProtoBuf文件编写及序列化 文章目录 ProtoBuf文件编写及序列化快速上手ProtoBuf创建.proto 文件指定Proto3语法Package声明符定义消息(message)定义消息字段编译命令 序列化与反序列化的使用小结 快速上手ProtoBuf 为了快速上手以及完整的使用ProtoBuf&#xff0c;我们将编写一…

Java高频面试之SE-22

hello啊&#xff0c;各位观众姥爷们&#xff01;&#xff01;&#xff01;本baby今天又来了&#xff01;哈哈哈哈哈嗝&#x1f436; Java中的Optional了解多少&#xff1f; 在 Java 中&#xff0c;Optional 是 Java 8 引入的一个容器类&#xff0c;用于显式处理可能为 null 的…

250217-数据结构

1. 定义 数据结构是数据的存储结构&#xff0c;即数据是按某些结构来存储的&#xff0c;比如线性结构&#xff0c;比如树状结构等。 2. 学习意义 数据结构是服务于算法的&#xff0c;为了实现算法的高效计算&#xff0c;所以将数据按特定结构存储。比如使用快速插入或删除的…

PyCharm2024使用Python3.12在Debug时,F8步进时如同死机状态

在使用时PyCharm2024&#xff0b;Python3.12&#xff0c;在程序进行调试时&#xff0c;按F8步进时如同死机状态。 1、相同的程序在PyCharm2023&#xff0b;Python3.9时是没有问题的&#xff0c;因此决定重装PyCharm2023&#xff0b;Python3.9&#xff0c;进行调试——调试OK。 …

C/C++ | 每日一练 (2)

&#x1f4a2;欢迎来到张胤尘的技术站 &#x1f4a5;技术如江河&#xff0c;汇聚众志成。代码似星辰&#xff0c;照亮行征程。开源精神长&#xff0c;传承永不忘。携手共前行&#xff0c;未来更辉煌&#x1f4a5; 文章目录 C/C | 每日一练 (2)题目参考答案封装继承多态虚函数底…

DeepSeek应用-一秒对书本要点分析并创建思维脑图

2025年开始啦&#xff0c;从DeepSeek的火爆程度来看&#xff0c;今年必须紧盯DS的发展&#xff0c;AI不会淘汰人&#xff0c;AI只会淘汰不会使用的人。从文心一言、豆包、Kimi到DS,基本上从功能上大致相同&#xff0c;但是DeepSeek的开源着实在眼界和格局上更胜一筹&#xff0c…

4、IP查找工具-Angry IP Scanner

在前序文章中&#xff0c;提到了多种IP查找方法&#xff0c;可能回存在不同场景需要使用不同的查找命令&#xff0c;有些不容易记忆&#xff0c;本文将介绍一个比较优秀的IP查找工具&#xff0c;可以应用在连接树莓派或查找IP的其他场景中。供大家参考。 Angry IP Scanner下载…

android 的抓包工具

charles 抓包工具 官网地址 nullCharles Web Debugging Proxy - Official Sitehttps://www.charlesproxy.com/使用手册一定记得看官网 SSL Certificates • Charles Web Debugging Proxy http请求&#xff1a; 1.启动代理&#xff1a; 2.设置设备端口 3.手机连接当前代理 …

Java常用工具类详解

目录 一、Java 中的数学利器&#xff1a;java.lang.Math 类详解 1.常用属性 2.常用方法 ⑴.static int abs(int a) ⑵.static double ceil(double a) ⑶.static double floor(double a) ⑷.static int max(int a, int b) 和 static int min(int a, int b) ⑸.static do…