`Leetcode`224使用栈和逆波兰式解决此类计算器问题

Leetcode224使用栈和逆波兰式解决此类计算器问题

示例 1:

输入:s = “1 + 1”
输出:2
示例 2:

输入:s = " 2-1 + 2 "
输出:3
示例 3:

输入:s = “(1+(4+5+2)-3)+(6+8)”
输出:23

提示:

1 <= s.length <= 3 * 105
s 由数字、’+’、’-’、’(’、’)’、和 ’ ’ 组成
s 表示一个有效的表达式

题解:

方式一:栈

由于仅有加减和括号因此,特别是括号,记得当初学数据结构栈时,判断括号就是通过栈这种数据结构进行判断的,因此这题首先想到了用栈。那用栈来存储什么呢?

先从最简单的开始思考:

  1. 如果遇到空格, 一般是用来将数字和运算符或者括号之间才会出现,对数字前的正负没有影响。遍历时可以直接跳过.
  2. 在计算当中难免会遇到数层括号,而括号内的正负,也和括号前的正负有关,括号的层数有关,因此,我们不妨设计一个栈的数据结构用来存储每一层的正负:即当进入括号时,我们将当前进入括号前的绝对正负添加到栈顶,然后每进入一个括号就将进入括号前的绝对正负添加到栈顶,如果出括号就将栈顶判断正负的数弹出。然后判断正负时,我们便仅需要判断当前遇到的符号为+还是-,判断sign正负由3和4解答
  3. 如果遇到+,显然后面的数字的正负只取决于最后存储在栈底的正负有关即sign = pos_or_neg[-1].
  4. 遇到-时,我们不知道前面有多少个-号对这个减号起作用,但是我们使用了pos_or_neg存储在栈顶的
  5. 然后当遇到数字并且没有超出该字符串的范围时:我们先将这个数判断出来后乘以它的绝对正负加到result中,最后结束while循环返回。
  6. 时间复杂度为O(n),空间复杂度为O(n)
class Solution:
    def calculate(self, s: str) -> int:
        pos_or_neg = [1]
        n = len(s)
        i = 0
        result = 0
        sign = 1
        while i < n:
            if s[i] == ' ':
                i += 1
            elif s[i] == '+':
                 i += 1
                 sign = pos_or_neg[-1] 
            elif s[i] == '-':
                i += 1
                sign = - pos_or_neg[-1]
            elif s[i] == '(':
                pos_or_neg.append(sign)
                i += 1
            elif s[i] == ')':
                pos_or_neg.pop()
                i += 1
            else:
                num = 0
                while i< n and s[i].isdigit():
                    num =10*num + int(s[i])
                    i += 1
                result +=sign*num
        return result 

方式二 逆波兰式(后缀表达式)

解题思路

采用常规的思路,先将中缀表达式转换成后缀表达式,接着再计算后缀表达式。

中缀表达式转后缀表达式

后缀表达式使用string存储,转后缀表达式的过程中使用一个操作符栈存储操作符,后缀表达式中数字和操作数之间均有一个空格分隔开。
遍历中缀表达式,空格跳过,遇到数字则读取(注意可能有多位数字,我这里只把负号看作操作符而不是数字前的符号),并加到后缀表达式中。
遇到左括号,压入操作符栈中。
遇到操作符,遵循一条规则——若栈顶的操作符优先级高于或等于当前符号优先级,则不断出栈并加到后缀表达式中,直到栈顶操作符的优先级小于当前符号优先级(’('的优先级最小)。接着将当前操作符入栈。
遇到右括号,不断出栈并加入到后缀表达式中,直到左括号也出栈。

计算后缀表达式

使用一个操作数栈,遍历后缀表达式,遇到数字将其压入栈中,遇到操作符则将栈顶两个操作数弹出并计算,接着压回栈中,结束后操作数栈只剩下一个数字,返回即为结果。

注意:由于我将所有数字视为整数,所以负号看成操作符,但如果类似"-1+3"或"1+(-1+2)"类似的表达式,会有问题,因为减号缺少左操作数,所以我们可以事先在操作数栈中压入一个0,既不影响大小,也解决了特例。

import re
class Solution(object):
    def calculate(self, s):
#首先将表达式转换为逆波兰表达式
        s=re.sub(' ', '', s)  # 去除空格
        output=[]
        stack=[]
        i=0
        while i <len(s):
            #如果是数字直接输出
            if s[i]!='(' and s[i]!=')' and s[i]!='+' and s[i]!='-':
                j=i+1
                while j<len(s) and s[j]!='(' and s[j]!=')' and s[j]!='+' and s[j]!='-':
                    j=j+1
                output.append(int(s[i:j]))
                i=j
                continue
            #如果是操作符,因为本题只有加减,遇到操作符就将栈内左括号前的操作符全部输出,把当前操作符压栈
            if s[i]=='+' or s[i]=='-':
                while stack!=[] and stack[-1]!='(':
                    output.append(stack.pop(-1))
                stack.append(s[i])
                i=i+1
                continue
            #如果是左括号就压栈
            if s[i]=='(':
                stack.append(s[i])
                i=i+1
                continue
            #如果是右括号,就把栈内第一个左括号前的所有操作符输出
            if s[i]==')':
                while stack!=[] and stack[-1]!='(':
                    output.append(stack.pop(-1))
                stack.pop(-1)
                i=i+1
                continue
        #输出栈内剩余操作符
        while stack!=[]:
            output.append(stack.pop(-1))
#转换为逆波兰表达式之后,遍历整个表达式,遇到数字就压栈,
#遇到操作符就把栈顶两个数字出栈计算,把计算结果压栈,直到栈内只剩一个数字就是答案
        if len(s)>1 and (s[0]=='+' or s[0]=='-' or s[0]=='(' or s[0]==')'):
            output=[0]+output
        for i in range(len(output)):
            if output[i]!='+' and output[i]!='-':
                stack.append(output[i])
            else:
                a=stack.pop(-1)
                b=stack.pop(-1)
                if output[i]=='+':
                    stack.append(a+b)
                else:
                    stack.append(b-a)
        return stack[-1]

参考文献:

【1】https://leetcode-cn.com/problems/basic-calculator/comments/

【2】https://leetcode-cn.com/problems/basic-calculator/solution/227-ji-ben-ji-suan-qi-ii-c-chang-gui-si-86lqn/

猜你喜欢

转载自blog.csdn.net/weixin_45915507/article/details/114685144