leetcode分类刷题:栈(Stack)(二、基本计算器类型)

1、顺着“逆波兰表达式”的题目继续做了下推荐的基本计算器类型的几道题,我的天,是真的难,不愧是hard级别的难题
2、研究了好几天大佬的题解双栈解决通用「表达式计算」问题,还是不太明白为啥有一个新操作要入栈时,先把栈内可以算的都算了,先简单把大佬思路记录下来吧,后续再看

150. 逆波兰表达式求值

逆波兰表达式是一种后缀表达式,适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中

'''
150. 逆波兰表达式求值
根据 逆波兰表示法,求表达式的值。
有效的算符包括+、-、*、/。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
注意两个整数之间的除法只保留整数部分。
可以保证给定的逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
示例 1:
    输入:tokens = ["2","1","+","3","*"]
    输出:9
    解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
题眼:逆波兰表达式是一种后缀表达式,适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中
细节:两个整数之间的除法总是 向零截断的处理按照int(a/b)
'''

from typing import List


class Solution:
    def evalRPN(self, tokens: List[str]) -> int:
        stk = []
        for n in tokens:
            if n not in '+-*/':  # 入栈:元素不为符号
                stk.append(int(n))
            else:  # 出栈:
                b = stk.pop()
                a = stk.pop()
                if n == '+':
                    stk.append(a + b)
                elif n == '-':
                    stk.append(a - b)
                elif n == '*':
                    stk.append(a * b)
                else:  # 注意两个整数之间的除法只保留整数部分:Python3里的负数除法与C++的/不一样,需要int(/)写法
                    stk.append(int(a/b))
        return stk.pop()


if __name__ == "__main__":
    obj = Solution()
    while True:
        try:
            in_line = input().strip().split('=')[1].strip().split('"')[1: -1]
            tokens = [s for s in in_line if s != ',']
            print(tokens)
            print(obj.evalRPN(tokens))
        except EOFError:
            break

772. 基本计算器 III

这是一道会员题,同类型的还有224. 基本计算器227. 基本计算器 II,题意就是对输入的字符串表达式求出正确的±*/后的结果,表达式内还有括号,大佬的题解双栈解决通用「表达式计算」问题提供了通用解法,能把其它两题也全部通过掉

from typing import List
'''
772. 基本计算器 III
给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。整数除法仅保留整数部分。
你可以假设给定的表达式总是有效的。所有中间结果将在 [-2^31, 2^31 - 1] 的范围内。
注意:不允许使用任何将字符串作为数学表达式计算的内置函数,比如 eval() 。
提示:s 由整数和算符 ('+', '-', '*', '/') 及左右括号‘(’‘)’组成,中间由一些空格隔开;s 表示一个 有效表达式
示例 1:
    输入:s = "2*(5+5*2)/3+(6/2+8)"
    输出:21
思路:
'''


class Solution:
    op_map = {'+': 1, '-': 1, '*': 2, '/': 2, '%': 2, '^': 3}  # 定义运算符的优先级

    def calculate(self, s: str) -> int:
        s = self.deleteSpace(s)  # 将所有的空格去掉,也可以直接调用replace函数 s = s.replace(' ', '')
        nums = [0]  # 存放所有的数字:为了防止第一个数为负数,先往nums加个0
        ops = []  # 存放所有的操作,包括 (+-*/%^

        i = 0
        while i < len(s):
            if s[i] in '0123456789':  # 数字:从当前位置开始继续往后取,将整一个连续数字整体取出,加入nums
                num = 0
                while i < len(s) and s[i] in '0123456789':
                    num = num * 10 + int(s[i])
                    i += 1
                nums.append(num)
            elif s[i] == '(':  # 左括号:直接加入ops中,等待与之匹配的)
                ops.append(s[i])
                i += 1
            elif s[i] == ')':  # 右括号:使用现有的nums和ops进行计算,直到遇到左边最近的一个左括号为止,计算结果放到nums
                while ops[-1] != '(':
                    self.calc(nums, ops)
                ops.pop()
                i += 1
            elif s[i] in '+-*/%^':  # 运算符:有一个新操作要入栈时,先把栈内可以算的都算了(只有栈内运算符比当前运算符优先级高/同等,才进行运算)
                if i > 0 and s[i - 1] in '(+-':  # 考虑'(-8''(+8''++8''-+8''+-8''--8'等情况
                    nums.append(0)
                while len(ops) > 0 and ops[-1] != '(' and self.op_map[ops[-1]] >= self.op_map[s[i]]:
                    self.calc(nums, ops)
                ops.append(s[i])
                i += 1
        while len(ops) > 0:
            self.calc(nums, ops)
        return nums[-1]

    def calc(self, nums: List[int], ops: List[str]):
        if len(nums) < 2 or len(ops) == 0:
            return
        b = nums.pop()
        a = nums.pop()
        op = ops.pop()
        if op == '+':
            nums.append(a + b)
        elif op == '-':
            nums.append(a - b)
        elif op == '*':
            nums.append(a * b)
        elif op == '/':
            nums.append(int(a / b))
        elif op == '%':
            nums.append(a % b)
        elif op == '^':
            nums.append(a ** b)

    def deleteSpace(self, s: str) -> str:
        t = ""
        for ch in s:
            if ch == " ":
                continue
            t += ch
        return t


if __name__ == "__main__":
    obj = Solution()
    while True:
        try:
            in_line = input().strip().split('=')
            s = in_line[1].strip()[1: -1]
            print(obj.calculate(s))
        except EOFError:
            break

你可能感兴趣的:(leetcode分类刷题,leetcode,算法)