六、栈————相关算法探讨(持续更新中)


栈————相关算法探讨

  • 前言
  • 一、有效的括号
    • 1.1 思路分析
    • 1.2 解法探讨
      • 1.2.1 一次 for 循环,左括号入栈
      • 1.2.2 一次 for 循环,左括号入栈(使用字典)
      • 1.2.3 一次 for 循环,右括号进栈
      • 1.2.4 一次 for 循环,右括号进栈(使用字典)
  • 二、删除字符串中的所有相邻重复项
    • 2.1 思路分析
    • 2.2 解法探讨
      • 2.2.1 使用栈的思想
      • 2.2.2 使用双指针思想
  • 三、逆波兰表达式求值
    • 3.1 思路分析
    • 3.2 解法探讨
      • 3.2.1 使用栈
      • 3.2.2 简化(使用其他函数)
  • 总结


前言

  • 前面我们学习了栈的相关知识,下边我们结合 lecode 上有关栈的题目来加深对栈的认识。

一、有效的括号

  • 力扣算法题目第 20 题:给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。
  • 有效字符串需满足:
      1. 左括号必须用相同类型的右括号闭合。
      1. 左括号必须以正确的顺序闭合。
      1. 每个右括号都有一个对应的相同类型的左括号。
  • 示例 1:
    • 输入:s = “()”
    • 输出:true
  • 示例 2:
    • 输入:s = “()[]{}”
    • 输出:true
  • 示例 3:
    • 输入:s = “(]”
    • 输出:false
  • 示例 4:
    • 输入:s = “([])”
    • 输出:true

1.1 思路分析

  • 首先我们要判断有几种不匹配的情况,在写之前分析好,这样会事半功倍。
    • 1、字符串里边左括号多余,所以不匹配。
    • 2、字符串里右括号多余了,所以不匹配。
    • 3、括号没有多余,但是匹配不上。
  • 但还有一些技巧,在匹配左括号的时候,右括号先入栈,就只需要比较当前元素和栈顶相不相等就可以了,比左括号先入栈代码实现要简单的多了!

1.2 解法探讨

1.2.1 一次 for 循环,左括号入栈

  • 每当遍历到字符串中的左括号的时候,那就让左括号入栈,
  • 当匹配到右括号的时候,
    • 我们检查这时候的栈顶元素等不等于这时候的右括号 或者 栈是否为空,如果有一个条件满足,那就返回False
    • 如果栈顶元素匹配右括号的话,那就让栈顶元素出栈, 继续循环字符串中的下一个字符
  • 当遍历完字符串的时候,栈内如果还有元素的话,那说明没匹配完,返回False

时间复杂度 : O ( n ) O(n) O(n)

空间复杂度 : O ( n ) O(n) O(n)

代码演示:

class Solution:def isValid(self, s: str) -> bool:# 定义一个栈用来存放左括号stack = []# 定义一个tmp用来存放 所有向左的括号tmp = ['(','[','{']# 遍历传进来的字符串sfor item in s:# 如果 遍历到的这个括号 是属于向左的括号if item in tmp:# 将所有的向左的括号入栈stack.append(item)# 开始对 所有向右的 括号进行判断    elif item == ')':# 如果 stack为空 或者 栈顶元素不等于与之匹配的括号if not stack or stack[-1] != '(':# 那就返回 Falsereturn False# 如果 遍历到的右括号 跟栈顶元素 匹配的话, 栈顶元素出栈# stack.pop()else:stack.pop()# 跟上边相同elif item == ']':if not stack or stack[-1] != '[':return False# stack.pop()else:stack.pop()elif item == '}':if not stack or stack[-1] != '{':return False# stack.pop()else:stack.pop()else:return False # 当遍历完字符串的时候,如果栈内还有元素,那说明没匹配完全,返回Falsereturn True if not stack else False

1.2.2 一次 for 循环,左括号入栈(使用字典)

时间复杂度 : O ( n ) O(n) O(n)

空间复杂度 : O ( n ) O(n) O(n)

代码演示:

class Solution:def isValid(self, s: str) -> bool:# 定义一个栈用来存放左括号stack = []# 定义一个字典用来存放右括号right_dict = {')':'(',']':'[','}':'{'}# 开始遍历字符串sfor i in s:# 如果元素是 左括号 也就是字典中的Keyif i in right_dict.values():# 也就是左括号入栈stack.append(i)# 当遍历到的元素 为右括号的时候 判断栈是否为空 或者栈顶元素能不能匹配我们的右括号# elif not stack or stack[-1] != right_dict[i]:#     return False# # 走到这 说明匹配上了# else:#     stack.pop()# 当栈为空的时候,也就是字符串中没有 字符串进栈,或者当出栈以后栈为空elif not stack:return False# 当栈顶元素跟我们的右括号匹配的话,那栈顶元素就出栈elif stack[-1] == right_dict[i]:stack.pop()else:return False# 最后如果栈内还有元素的话,那就说明 没匹配完全,返回Falsereturn True if not stack else False    

1.2.3 一次 for 循环,右括号进栈

时间复杂度 : O ( n ) O(n) O(n)

空间复杂度 : O ( n ) O(n) O(n)

代码演示:

class Solution:def isValid(self, s: str) -> bool:# 定义一个栈用来存放右括号stack = []for item in s:# 当 遍历到左括号的时候那就右括号进栈if item == '(':stack.append(')')elif item == '[':stack.append(']')elif item == '{':stack.append('}')# 若遍历到右括号的时候,我们只需要比较栈顶元素跟遍历到的右括号相等不相等elif not stack or stack[-1] != item:return False# 走到这说明,说明栈顶元素跟遍历到的元素匹配上了,所以栈顶元素要出栈else:stack.pop()return True if not stack else False

1.2.4 一次 for 循环,右括号进栈(使用字典)

时间复杂度 : O ( n ) O(n) O(n)

空间复杂度 : O ( n ) O(n) O(n)

代码演示:

class Solution:def isValid(self, s: str) -> bool:stack = []mapping = {'(': ')','[': ']','{': '}'}for item in s:if item in mapping.keys():stack.append(mapping[item])elif not stack or stack[-1] != item: return Falseelse: stack.pop()return True if not stack else False

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

  • 力扣算法题目第 20 题:
    • 给出由小写字母组成的字符串 s,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
    • 在 s 上反复执行重复项删除操作,直到无法继续删除。
    • 在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。
  • 示例 1 :
    • 输入:“abbaca”
    • 输出:“ca”
    • 解释:例如,在 “abbaca” 中,我们可以删除 “bb” 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 “aaca”,其中又只有 “aa” 可以执行重复项删除操作,所以最后的字符串为 “ca”。
  • 提示
    • 1 <= s.length <= 1 0 5 10^5 105
    • s 仅由小写英文字母组成

2.1 思路分析

  • 我们可以使用栈的思想,遍历到一个元素就判断跟栈顶元素是否相等,如果相等的话,说明字符串中这两个字符重复,这时候让栈顶元素出栈即可,如果,栈顶元素跟遍历到的元素不同的话,这个元素入栈。
  • 当然我们还可以使用双指针:刚开始两个指针都指向第一个元素,fast指针开始走,并且比较该元素跟slow指针所指的元素是否相等,如果相等,删除这两个元素,并且slow指针往回退一个,fast指针继续往后走。

2.2 解法探讨

2.2.1 使用栈的思想

代码演示:

class Solution:def removeDuplicates(self, s: str) -> str:# 定义一个空栈,stack = []# 开始遍历字符串for i in s:# 如果栈不为空,并且栈顶元素等于遍历到的元素,那么栈顶元素出栈if stack and stack[-1] == i:stack.pop()# 走到这,说明栈为空或者栈顶元素不等于遍历到的元素,那就将该元素入栈else:stack.append(i)# 我们得到的 stack 相当于是列表,所以要将其转成字符串return ''.join(stack)

2.2.2 使用双指针思想

代码演示:

class Solution:def removeDuplicates(self, s: str) -> str:res = list(s)slow = fast = 0length = len(res)while fast < length:# 如果一样直接换,不一样会把后面的填在slow的位置res[slow] = res[fast]# 如果发现和前一个一样,就退一格指针if slow > 0 and res[slow] == res[slow - 1]:slow -= 1else:slow += 1fast += 1return ''.join(res[0: slow])

三、逆波兰表达式求值

  • 力扣算法题目第 150 题:给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。
    • 请你计算该表达式。返回一个表示表达式值的整数。
  • 注意
      1. 有效的算符为 ‘+’、‘-’、‘*’ 和 ‘/’ 。
      1. 每个操作数(运算对象)都可以是一个整数或者另一个表达式。。
      1. 两个整数之间的除法总是 向零截断 。
      1. 表达式中不含除零运算。
      1. 输入是一个根据逆波兰表示法表示的算术表达式。
      1. 答案及所有中间计算结果可以用 32 位 整数表示。
  • 示例 1:
    • 输入:tokens = [“2”,“1”,“+”,“3”,“*”]
    • 输出:9
    • 解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
  • 示例 2:
    • 输入:tokens = [“4”,“13”,“5”,“/”,“+”]
    • 输出:6
    • 解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6
  • 示例 3:
    • 输入:tokens = [“10”,“6”,“9”,“3”,“+”,“-11”,““,”/“,””,“17”,“+”,“5”,“+”]
    • 输出:22
    • 解释:该算式转化为常见的中缀算术表达式为:
      ((10 * ( 6 / ((9 + 3) * -11))) + 17) + 5
      = ((10 * ( 6 / (12 * -11))) + 17) + 5
      = ((10 * ( 6 / -132)) + 17) + 5
      = ((10 * 0) + 17) + 5
      = (0 + 17) + 5
      = 17 + 5
      = 22
  • 提示:
    • 1 <= tokens.length <= 1 0 4 10^4 104
    • tokens[i] 是一个算符(“+”、“-”、“*” 或 “/”),或是在范围 [-200, 200] 内的一个整数

3.1 思路分析

  • 逆波兰表达式是一种后缀表达式,所谓后缀就是指算符写在后面。
    • 平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
    • 该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。
  • 逆波兰表达式主要有以下两个优点:
    • 去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
    • 适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中

3.2 解法探讨

3.2.1 使用栈

时间复杂度 : O ( n ) O(n) O(n)

空间复杂度 : O ( n ) O(n) O(n)

代码演示:

class Solution:def evalRPN(self, tokens: List[str]) -> int:# 定义一个栈stack = []# 定义一个列表放 加减乘除 符号char_list = ['+', '-', '*', '/']# 开始遍历 字符串中的字符for token in tokens:# 如果是数字,那就入栈if token not in char_list:stack.append(token)# 如果运算符,那就从栈中取出来 两个数进行运算else:if token == '+':# 栈顶元素为 运算符后边的数,因为op2 = int(stack.pop())op1 = int(stack.pop())res = op1 + op2stack.append(res)elif token == '-':# 因为取出来是字符,字符不能运算,必须转成intop2 = int(stack.pop())op1 = int(stack.pop())res = op1 - op2stack.append(res)elif token == '*':op2 = int(stack.pop())op1 = int(stack.pop())res = op1 * op2stack.append(res)# 到这就是除法else:op2 = int(stack.pop())op1 = int(stack.pop())# 但是除法要向零截断,所以有这步res = op1 / op2 if op1*op2 > 0 else -(abs(op1)//abs(op2))stack.append(res)# 返回栈顶元素return int(stack.pop())      

3.2.2 简化(使用其他函数)

时间复杂度 : O ( n ) O(n) O(n)

空间复杂度 : O ( n ) O(n) O(n)

代码演示:

from operator import add, sub, muldef div(x, y):# 使用整数除法的向零取整方式return int(x / y) if x * y > 0 else -(abs(x) // abs(y))class Solution(object):op_map = {'+': add, '-': sub, '*': mul, '/': div}def evalRPN(self, tokens: List[str]) -> int:stack = []for token in tokens:if token not in {'+', '-', '*', '/'}:stack.append(int(token))else:op2 = stack.pop()op1 = stack.pop()stack.append(self.op_map[token](op1, op2))  # 第一个出来的在运算符后面return stack.pop()

总结

  • 以上就是用到了栈结构的相关题目。

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

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

相关文章

【日常记录-Java】Windows下查看Java进程完整的启动命令

1. 简介 jps是Java Virtual Machine Process Status Tool的缩写&#xff0c;其会列出所有正在运行的Java进程ID以及类名。 wmic是Windows Management Instrumentation Command-line的缩写&#xff0c;其允许用户与wmi服务进行交互&#xff0c;提供了一种标准化的方法来访问和操…

ctfshow(151->154)--文件上传漏洞--.user.ini

Web151 进入界面&#xff1a; 审计&#xff1a; 提示是前台校验。 存在图片上传。 思路&#xff1a; 先编写一个一句话木马文件&#xff1a; //shell.php <?php eval($_POST[1]); ?>既然是前端校验&#xff0c;我们查看页面源代码找到相关的校验内容&#xff1a…

Ubuntu使用Tesla P4配置Anaconda+CUDA+PyTorch

我们之前测试了在Windows系统如何安装Tesla M4&#xff08;成了&#xff01;Tesla M4Windows 10AnacondaCUDA 11.8cuDNNPython 3.11&#xff09;&#xff0c;前面安装好了Ubuntu 22.04.4的操作系统&#xff08;Ubuntu 22.04.4安装Docker引擎&#xff09;。今天&#xff0c;简单…

少儿编程参培意愿地图:一二线城市热情高涨,低线城市市场待挖掘

随着少儿编程的普及&#xff0c;编程教育逐渐走进越来越多家庭。然而&#xff0c;少儿编程的地域分布显示出明显的差异&#xff1a;在一二线城市中&#xff0c;家长对少儿编程的接受度和参与度显著高于低线城市。本文将通过对地域分布和家长态度的分析&#xff0c;探讨少儿编程…

基于SSM演出道具租赁系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;商家管理&#xff0c;道具类型管理&#xff0c;道具出租管理&#xff0c;租赁订单管理&#xff0c;道具归还管理&#xff0c;系统管理 商家账号功能包括&#xff1a;系统首页&…

【Spring】Spring 核心和设计思想

Spring 核心和设计思想 1.什么是 Spring1.1 传统程序开发1.2 控制反转程序开发 2.理解 Spring IoC 1.什么是 Spring 我们通常所说的 Spring 指的是 Spring Framework&#xff08;Spring 框架&#xff09;&#xff0c;它是⼀个开源框架&#xff0c;有着活跃而庞大的社区&#x…

【Java】-- 内部类

文章目录 1. 静态内部类&#xff08;重要&#xff09;2. 实例内部类&#xff08;重要&#xff09;3. 局部内部类&#xff08;很少用&#xff09;4. 匿名内部类&#xff08;使用较多&#xff09;4.1 第一种写法&#xff08;类&#xff09;4.1 第二种写法&#xff08;接口) 当一个…

【C语言学习笔记】

C语言发展史&#xff1a; 1960 原型A语言->ALGOL语言 1963 CPL语言1967 BCPL1970 B语言1973 C语言 C语言特点&#xff1a; 基础性语言语法简洁 紧凑 方便 灵活(得益于指针)运算符 数据结构丰富结构化 模块化编程移植性好 执行效率…

STL学习-无序容器-unordered set和unorderde multiset

1.定义及初始化 #include <unordered set> #include <iostream> using namespace std; //输出s中的所有元素 template<typename T> void Show(const T& s) { for(auto&x:s) cout << x<<" ";cout << endl; } int main()…

docker-高级(待补图)

文章目录 数据卷(Volume)介绍查看方法删除方法绑定方法匿名绑定具名绑定Bind Mount 数据卷管理 网络bridge(桥接模式 默认)HOST(主机模式)Nonecontainer(指定一个容器进行关联网络共享)自定义(推荐)docker network 命令创建网络docker network create 实例展示-自定义实例展示-…

玩转Docker | Docker基础入门与常用命令指南

玩转Docker | Docker基础入门与常用命令指南 引言基本概念help帮助信息常用命令管理镜像运行容器构建镜像其他Docker命令整理结语引言 Docker 是一种开源的应用容器引擎,它允许开发者将应用程序及其依赖打包进一个可移植的容器中,然后发布到任何流行的 Linux 机器上。这大大简…

基于SSM医药进出口交易系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;商品信息管理&#xff0c;仓储部门管理&#xff0c;供应部门管理&#xff0c;业务部门管理&#xff0c;客户管理&#xff0c;财务部管理 业务部门账号功能包括&#xff1a;系统首页&#xff0c;个人中…

2024年大湾区杯粤港澳金融数学建模赛题浅析——助攻快速选题

一图流 赛题难度 A:B2:1 选题人数 A:B2:3 A题&#xff1a;证券市场投资风险控制模型设计 问题简述 随着金融市场的发展&#xff0c;系统性风险的管理变得越来越重要。本题要求通过量化方法测度和监测系统性风险&#xff0c;设计风险计量指标&#xff0c;并基于这些指标构建预…

胡壮麟《语言学教程》第五版PDF英文版+中文版翻译

胡壮麟《语言学教程》中文版&#xff1a;https://pan.quark.cn/s/9491130ec572 《语言学教程》&#xff08;英文版&#xff09;是一部经典的语言学教材&#xff0c;自 1988 年面世以来&#xff0c;被众多高校广泛采用&#xff0c;长销不衰。该教材自出版以来不断修订&#xff…

在浏览器和Node.js环境中使用Puppeteer的Rollup与Webpack打包指南

Puppeteer是一个Node.js库&#xff0c;它提供了一套高级API来通过DevTools协议控制Chrome或Chromium。虽然Puppeteer通常在服务器端使用&#xff0c;但有时你可能需要在浏览器环境中使用它的某些功能。本文将介绍如何使用Rollup和Webpack来打包包含Puppeteer或其轻量级版本Pupp…

C# 如何处理 WebSocket 连接异常

在 C# 中使用 WebSocket 进行通信时&#xff0c;处理连接异常是确保应用程序稳定性和可靠性的重要环节。本文将详细介绍如何在 C# 中有效地处理 WebSocket 连接异常&#xff0c;并附带代码示例进行拆分讲解。 一、理解 WebSocket 连接异常 WebSocket 连接可能会由于多种原因出现…

基于Pycharm和Django模型技术的数据迁移

1.配置数据库 在trip_server/settings.py中修改配置&#xff1a; 其格式可访问官网&#xff1a;Settings | Django documentation | Django 1.1 配置数据库 文件地址&#xff1a;trip_server/settings.py 配置前需要创建&#xff08;NaviCat&#xff09;个人数据库 "…

java访问华为网管软件iMaster NCE的北向接口

最近做的一个项目&#xff0c;需要读取华为一个叫iMaster NCE的网管软件的北向接口。这个iMaster NCE&#xff08;以下简称NCE&#xff09;用于管理项目的整个网络&#xff0c;尤其是光网络。业主要求我们访问该软件提供的对外接口&#xff0c;读取一些网络信息&#xff0c;比如…

创造tips的秘籍——PHP回调后门

0x00 前言 php中包含回调函数参数的函数&#xff0c;具有做后门的潜质。 我就自己给这类webshell起了个名字&#xff1a;回调后门。 0x01 回调后门的老祖宗 php中call_user_func是执行回调函数的标准方法&#xff0c;这也是一个比较老的后门了&#xff1a; call_user_func…

InstructIR: High-Quality Image Restoration Following Human Instructions 论文阅读笔记

这是Radu大佬所在的Wrzburg大学的computer vision lab实验室发表在ECCV2024上的一篇论文&#xff0c;代码开源。文章提出了一种文本引导的All-in-One的restoration模型&#xff0c;如下图所示&#xff1a; 这个工作其实跟"InstructPix2Pix: Learning to Follow Image Edit…