DAY 11 | 栈与队列02

题目  20. 有效的括号 

题目链接

题目描述:

给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。

有效字符串需满足:

  • 左括号必须用相同类型的右括号闭合。
  • 左括号必须以正确的顺序闭合。
  • 注意空字符串可被认为是有效字符串。

示例 1:

  • 输入: "()"
  • 输出: true

示例 2:

  • 输入: "()[]{}"
  • 输出: true

示例 3:

  • 输入: "(]"
  • 输出: false

示例 4:

  • 输入: "([)]"
  • 输出: false

示例 5:

  • 输入: "{[]}"
  • 输出: true

解题思路:

首先括号都是成对的,所以长度为奇数的肯定无效

长度为偶数的情况下,用栈来做,把括号分为两种:

  • 左括号 ( [ { 
  • 右括号 ) ] }

循环整个输入,当检测到为左括号时,往栈里面加对应的右括号。

检测到位右括号时,而且栈头元素为一样的右括号,则pop掉栈头元素。

最后检查栈,如果为空说明匹配完了,返回true;如果没有,说明匹配不合格。

代码:

class Solution:
    def isValid(self, s: str) -> bool:
        #define a stack to store the right part
        stack=[]
        #define a dict store the left and right
        my_dict={'(':')','{':'}','[':']'}

        if len(s)%2!=0:
            return False
        else:
            for i in s:
                if i in my_dict.keys():
                    stack.append(my_dict[i])
                elif not stack or stack[-1] != i: 
                    return False
                else: 
                    stack.pop()
        return True if not stack else False

        

复杂度:

函数的时间和空间复杂度都是 O(n)。

题目1047. 删除字符串中的所有相邻重复项

题目链接

题目描述:

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

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

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

示例:

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

提示:

  • 1 <= S.length <= 20000
  • S 仅由小写英文字母组成。

解题思路:

  1. 我们首先创建一个空的栈 stack

  2. 然后,我们遍历输入的字符串 s。对于 s 中的每一个字符 i,我们做以下处理:

    • 如果栈不为空,并且栈顶的字符(stack[-1])与当前字符 i 相同,我们就从栈顶弹出一个字符。这是因为我们发现了一对连续出现的重复字符。
    • 否则,我们就把当前字符 i 压入栈中。
  3. 遍历完 s 之后,栈中的字符就是我们想要的结果。我们只需要将栈中的字符连成一个字符串即可。在Python中,可以使用 ''.join(stack) 来实现这一点。

代码:

class Solution:
    def removeDuplicates(self, s: str) -> str:
        stack=[]
        for i in s:
            if stack and i==stack[-1]:
                stack.pop()
            else:
                stack.append(i)
        return ''.join(stack)
                
                class Solution:
    def removeDuplicates(self, s: str) -> str:
        stack=[]
        for i in s:
            if stack and i==stack[-1]:
                stack.pop()
            else:
                stack.append(i)
        return ''.join(stack)
                
                

复杂度:

时间复杂度:我们需要遍历一次输入的字符串 s,对于 s 中的每个字符,我们执行的操作(即比较和可能的压栈或出栈操作)都可以在常数时间内完成。因此,总的时间复杂度是 O(n)。

空间复杂度:我们用到了一个额外的栈 stack 来存储字符。在最坏的情况下(例如,当 s 中没有连续的重复字符时),我们需要把 s 中的所有字符都压入栈中。因此,总的空间复杂度是 O(n)。

题目  150. 逆波兰表达式求值

题目链接

题目描述: 

根据 逆波兰表示法,求表达式的值。

有效的运算符包括 + ,  - ,  * ,  / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。

说明:

整数除法只保留整数部分。 给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。

示例 1:

  • 输入: ["2", "1", "+", "3", " * "]
  • 输出: 9
  • 解释: 该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9

解题思路:

  1. 首先创建一个空栈。

  2. 遍历给定的逆波兰表达式(是一个字符串数组)。

  3. 对于遇到的每个元素:

    • 如果它是一个操作符('+'、'-'、'*'、'/'),那么从栈中弹出两个元素作为操作数,进行相应的运算,并将结果再压入栈中。
    • 如果它是一个数字,那么直接将其压入栈中。
  4. 遍历结束后,栈中应该只剩下一个元素,这就是整个表达式的计算结果。

代码:

注意eval函数的用法,

除法操作("/")在 Python 中的结果是浮点数,即使是两个整数相除。

因此,为了保持栈中元素的一致性(即都是字符串类型的整数),以及为了符合题目要求(即所有的除法运算结果都需要取整),这里用 int() 函数将 eval 的结果转化为整数,然后再将其以字符串形式存入栈中。

class Solution:
    #eval: 将字符串str当成有效的表达式来求值并返回计算结果
    def evalRPN(self, tokens: List[str]) -> int:
        stack=[]
        for item in tokens:
            if item not in {"+", "-", "*", "/"}:
                stack.append(item)
            else:
                first_num, second_num = stack.pop(), stack.pop()
                stack.append(
                    int(eval(f'{second_num} {item} {first_num}'))   # 第一个出来的在运算符后面
                )
        return int(stack.pop()) # 如果一开始只有一个数,那么会是字符串形式的,所以为了保险起见加一个int

复杂度:

时间复杂度:我们需要遍历一次输入的 tokens 数组,对于 tokens 中的每个元素,我们执行的操作(即比较和可能的压栈或出栈操作)都可以在常数时间内完成。因此,总的时间复杂度是 O(n)。

空间复杂度:我们用到了一个额外的栈 stack 来存储数字。在最坏的情况下(例如,当 tokens 中所有的元素都是数字时),我们需要把 tokens 中的所有元素都压入栈中。因此,总的空间复杂度是 O(n)。

额外知识点:

逆波兰表达式(Reverse Polish Notation, RPN)实际上是二叉树的后序遍历(Post-order Traversal)。

如果我们将一个算术表达式看作一个二叉树,其中叶节点是操作数(即数字),非叶节点是操作符(如 +、-、*、/),那么:

  • 中序遍历(In-order Traversal)会得到中缀表达式,即常规的算术表达式,例如 "(2 + 3) * 4"。
  • 前序遍历(Pre-order Traversal)会得到波兰表达式(Polish Notation,PN),例如 "* + 2 3 4"。
  • 后序遍历(Post-order Traversal)则会得到逆波兰表达式(Reverse Polish Notation, RPN),例如 "2 3 + 4 *"。

所以,逆波兰表达式可以看作是算术表达式二叉树的后序遍历。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值