【leetcode】基本计算器II

堆栈

首先想到的思路是,遍历字符串

  • 空格:什么都不操作
  • 加号或者减号:入栈
  • 数字:入栈
  • 乘号或者除号:弹出栈顶元素,和符号后的数字做运算,将运算结果入栈

遍历后的堆栈只有数字、加号或者减号,再遍历一遍堆栈,运算结果就可以了

然而,事实不是那么简单的,有这么几个坑坑

  • 数字和数字之间有空格,数字可能超过1位,那么需要记录一个数字变量num,更新num的值(*)
  • 栈内的数字是int类型,字符串的数字是字符类型,字符类型需要转换成int类型

个人推测,(*)部分增加了一些常数项的时间,拉低了计算效率

class Solution:
    def calculate(self, s: str) -> int:
        '''
        单个栈,遍历两次
        '''
        stack = []
        # s = ''.join(s.split()) # Note(*)去除空格
        i = 0
        while i < len(s):
            if s[i] == '+':
                stack.append(s[i])
                i += 1
            elif s[i] == '-':
                stack.append(s[i])
                i += 1
            elif s[i] == '*':
                num1 = stack.pop()
                # 找到后面的数字
                num2 = 0 
                i += 1
                while i < len(s) and s[i] not in ['+', '-', '*', '/']: # Note(2)
                    if s[i] == ' ': # Note(1)
                        i += 1 # Note(1)
                    else: # Note(1)
                        num2 = num2*10 + int(s[i])
                        i += 1
                stack.append(num1 * num2)
            elif s[i] == '/':
                num1 = stack.pop()
                # 找到后面的数字
                num2 = 0 
                i +=1 
                while i < len(s) and s[i] not in ['+', '-', '*', '/']:
                    if s[i] == ' ': # Note(1)
                        i += 1 # Note(1)
                    else: # Note(1)
                        num2 = num2*10 + int(s[i])
                        i += 1
                stack.append(int(num1 / num2))
            elif s[i] == ' ':
                i += 1
            else:
                # s[i]是数字, '0' <= s[i] <= '9'
                num = 0
                while i < len(s) and s[i] not in ['+', '-', '*', '/']:
                    if s[i] == ' ': # Note(1)
                        i += 1 # Note(1)
                    else: # Note(1)
                        num = num*10 + int(s[i])
                        i += 1
                stack.append(num)

        res = stack[0]
        j = 1
        while j < len(stack):
            if stack[j] == '+':
                j += 1
                num = stack[j]
                res = res + num
                j += 1
            elif stack[j] == '-':
                j += 1
                num = stack[j]
                res = res - num
                j += 1
        return res     
  • Note(1)和Note(*)单独处理空格
  • 时间复杂度:O(N),然而Note(2)部分的循环增加了多次的判断,导致O(N)的N前面有个常数,算法整体上的运算时间增加了,stack堆栈里边判断加号还是减号也要花一点点时间,那么看看下面的大佬们的解法吧~
  • 空间复杂度:O(N),堆栈存储是O(N)

单次遍历,时间复杂度和空间复杂度O(N)

参考题解:https://leetcode-cn.com/problems/basic-calculator-ii/solution/ji-ben-ji-suan-qi-ii-by-leetcode-solutio-cm28/

class Solution:
    def calculate(self, s: str) -> int:
        '''
        Solution 2: 另一种思路,不得不说不要吝惜常数变量
        '''
        stack = []
        sign = '+' # 记录num前的符号,初始值是正
        num = 0 # 当前的数字
        n = len(s)
        for i in range(0, n):
        	# Note(1)
            if '0' <= s[i] <= '9':
                num = num * 10 + int(s[i])
            # Note(2)
            if i == n-1 or s[i] in ['+', '-', '*', '/']:
                # 触发入栈条件1: 遍历到符号的时候,触发上一次计算或者入栈的操作
                # 触发入栈条件2: 遍历到了字符串的最后一个位置
                if sign == '+':
                    stack.append(num)
                elif sign == '-':
                    stack.append(-num)
                elif sign == '*':
                    stack.append(stack.pop() * num)
                else:
                    # sign == '/':
                    stack.append(int(stack.pop() / num))
                sign = s[i] # 更新运算符号
                num = 0 # num重置为0

        # 累加堆栈的元素,是返回结果
        res = 0
        for item in stack:
            res += item

        return res

不得不说,增加一些辅助变量,很妙啊~
维护两个全局变量

  • num: 数字,将会是入栈的数字
  • sign: num的运算符号,数字入栈的符号
  • 入栈条件1: 遍历到运算符号
  • 入栈条件2: 遍历到字符串的最后(⭐️这一条件很容易被遗漏)
  • 一直在更新数字,数字更新结束一个,判断这个数字num以什么样的方式入栈
    • sign = ‘+’, num入栈
    • sign = ‘-’ , num相反数入栈
    • sign = ‘*’ , pop出来栈顶元素,和num相乘后,运算结果入栈
    • sign = ‘/’, pop出来栈顶元素,除以num取整后,运算结果入栈
  • Note(1)和Note(2)两个部分之间没有else的关系,这也很重要啊,遍历到每个元素的时候都去判断下有没有遇到新的运算符号,如果遇到了新的运算符号,那么执行入栈的操作

遍历结束后的堆栈中只有数字,数字和数字之间的关系只有加法的关系,节省了更多的时间

哈哈哈,小伙伴们,千万不要吝惜指针和辅助变量哇~
今天的分享就到这里了,我们下次再见啦~
喜欢的话请收藏、点赞、转发啊~

复习重写代码

class Solution:
    def calculate(self, s: str) -> int:
        stack = [] # 堆栈
        num = 0 # 数字的值
        res = 0 # 存放结果
        sign = '+' # 数字前的符号
        i = 0
        while i <= len(s):
            # 把符号更新到sign
            if i==len(s) or s[i] in ['+', '-', '*', '/']:
                # 入栈
                if sign == '+':
                    stack.append(num)                    
                elif sign == '-':
                    stack.append(-num)
                elif sign == '*':
                    stack.append(stack.pop() * num)
                elif sign == '/':
                    stack.append(int(stack.pop() / num))
                # 更新sign,num清零            
                if i<len(s):
                    sign = s[i]
                i += 1
                num = 0   
                
            # 空格,过滤
            elif s[i] == ' ':
                i += 1
            
            # 数字,找到最后一个不是数字的,假设数字和数字之间没有空格
            elif s[i] >= '0' and s[i] <= '9':
                while i < len(s) and s[i] >= '0' and s[i] <= '9':
                    num = num*10 + int(s[i]) # 注意这里要把s[i]从字符变成int类型
                    i += 1
                        
        # 栈里元素累加
        while stack != []:
            res = res + stack.pop()
        return res

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值