zoukankan      html  css  js  c++  java
  • 算法50----基本计算器【栈】

    一、题目:基本计算器【只有 + ,- ,以及括号】

    实现一个基本的计算器来计算一个简单的字符串表达式的值。

    字符串表达式可以包含左括号 ( ,右括号 ),加号 + ,减号 -非负整数和空格  

    示例 1:

    输入: "1 + 1"
    输出: 2
    

    示例 2:

    输入: " 2-1 + 2 "
    输出: 3

    示例 3:

    输入: "(1+(4+5+2)-3)+(6+8)"
    输出: 23

    非递归思路:

    栈:

    采用栈存储遇到 ( 之前的结果。

    遇到 ),将栈中最后一个数弹出计算结果。

    处理过程:

    res记录结果,stack用来存结果【遇到()先存前面的结果】,sign记录符号+、-

    1. 遇到 + :sign = 1
    2. 遇到 - :sign = -1
    3. 遇到数字:【考虑‘42’两个字母一起的情况,采用循环】结果 res  += int (42) * sign
    4. 遇到 ’( ’:stack中加入 res和sign
    5. 遇到‘ ) ‘:stack弹出最后一个元素和倒数第二个元素来更新res
     

    代码1:

        def calculate(self, s):
            """
            :type s: str
            :rtype: int
            """
            if not s:
                return 0
    #stack存储遇到括号(之前的计算结果res
    #temp记录数字,【如‘42’两个数字一起出现的情况】
    #sign记录符号+,-
    #res记录计算结果
            stack,temp = [],''
            sign , res , i = 1 , 0 , 0 
            while i < len(s):
    #遇到字母:如果有两个数字同时出现,采用循环解决
    #res结果把符号相乘
                if s[i].isdigit():
                    while i<len(s) and s[i].isdigit():
                        temp += s[i]
                        i += 1
                    i -= 1
                    res += int(temp)*sign
    #遇到+,-,sign=1,-1
                elif s[i] == '+':
                    sign = 1
                elif s[i] == '-':
                    sign = -1 
    #遇到(,将前面的res和符号sign存入栈中,初始化res和sign
                elif s[i] == '(':
                    stack.append(res)
                    stack.append(sign)
                    res,sign = 0,1
    #遇到),将栈中原来的结果res和符号sign弹出和当前的res更新得到新的结果res
                elif s[i] == ')':
                    if stack:
                        sign_tmp = stack.pop()
                        res_tmp = stack.pop()
                    res = res_tmp + res*sign_tmp
                i += 1
                temp= ''
            return res    

    二、题目:基本计算器二【只有加减乘除,没有括号】

    实现一个基本的计算器来计算一个简单的字符串表达式的值。

    字符串表达式仅包含非负整数,+-*/ 四种运算符和空格  。 整数除法仅保留整数部分。

    示例 1:

    输入: "3+2*2"
    输出: 7
    

    示例 2:

    输入: " 3/2 "
    输出: 1

    示例 3:

    输入: " 3+5 / 2 "
    输出: 5

    非递归思路1:

    • 遇到数字:num存储
    • 遇到符号:
    1. +:栈存储:+num
    2. -:栈存储:-num
    3. *:num = 栈弹出最后一个元素 * num,再存入栈中
    4. /:num = 栈弹出最后一个元素 / num,再存入栈中

    如:'45/9',先num = 45,然后45前面默认为+ 符号,将45存入栈中,然后 sign =  / ,num = 9,判断sign == '/',将45弹出与num==9相除。

    即每个数字与其前面的符号相对应,sign和num。

    代码1:

    def calculate(self, s):
        if not s:
            return "0"
        stack, num, sign = [], 0, "+"
        for i in range(len(s)):
            if s[i].isdigit():
                num = num*10+ord(s[i])-ord("0")
            if (not s[i].isdigit() and not s[i].isspace()) or i == len(s)-1:
                if sign == "-":
                    stack.append(-num)
                elif sign == "+":
                    stack.append(num)
                elif sign == "*":
                    stack.append(stack.pop()*num)
                else:
                    tmp = stack.pop()
                    if tmp//num < 0 and tmp%num != 0:
                        stack.append(tmp//num+1)
                    else:
                        stack.append(tmp//num)
                sign = s[i]
                num = 0
        return sum(stack)

    非递归思路2:

    栈:

    • 遇到数字:就将数字存入栈中。【考虑两个数字一起出现的情况】
    • 遇到 * 或 / 就将乘或者除计算结束再存入栈中。【其中还要考虑是数字的情况】
      • 将栈最后一个元素弹出,然后与 【乘号或者除号后面一个元素的数字】进行计算得到新的结果再存进栈中
    • 遇到加减,sign = 1或-1

    结果:

    将栈中所有元素加总就可以了

    代码2:

    def calculate(self, s):
            """
            :type s: str
            :rtype: int
            """
            if not s:
                return 0
            # return eval(s)
            stack = []
            res,sign,i= 0,1,0
            num = ''
            ca = True
            while i < len(s):
                ss = s[i]
    #数字,考虑两个数字出现的情况,用循环
                if ss.isdigit():
                    while i<len(s) and s[i].isdigit():
                        num += s[i]
                        i += 1
                        ca = False
                    stack.append(int(num)*sign)
    #加减sign = 1或者-1
                elif ss == '+':
                    sign = 1
                elif ss == '-':
                    sign = -1
    #乘号,
                elif ss == '*':
                    #可能后面是空白符号
                    while not s[i].isdigit():
                        i += 1
                    #考虑两个数字一起出现
                    while i<len(s) and s[i].isdigit():
                        num += s[i]
                        i += 1
                        ca = False
                    #将栈最后一个元素和乘号*后面一个数字相乘
                    res = stack.pop() * int(num)
                    #将结果存入栈中
                    stack.append(res)
    #除号
                elif ss == '/':
                    value = stack.pop()
                    while not s[i].isdigit():
                        i += 1
                    while i<len(s) and s[i].isdigit():
                        num += s[i]
                        i += 1
                        ca = False
                    #m是用来限制除法取整的,如果除的结果是负数,则结果要加1,正数不用
                    m = value//int(num)
                    if value % int(num) != 0:
                        m += 1 if m < 0 else 0
                    #将除的结果加入栈中
                    res = int(m)
                    stack.append(res)
                if ca:
                    i += 1
                num , ca = '',True
            return sum(stack)                    

    三、题目:基本计算器三【既有乘除又有括号】

    这道题将一和二结合,就是遇到括号就递归,别的就都与题目二一样。

    思路:采用栈存储数字和加减符号,乘除在放入栈中已计算出结果。变量pre记录数字。括号就递归。

    1、遇到数字:采用pre变量保存。

    2、遇到符号:存入栈中,存入之前先把栈中的乘除结果算出来

    3、遇到左括号:递归计算

    4、遇到右括号:计算栈中的结果。

    def getValue(s):
        if not s:
            return 0
        return value(list(s),0)[0]
    #递归函数,遇到左括号
    def value(arr,i):
        deque = []
        pre = 0
        while i < len(arr) and arr[i] != ')':
            #如果是数字,用pre变量保存
            if arr[i].isdigit():
               pre = pre * 10 + int(arr[i])
               i += 1
            #如果是符号,加入栈中,但先要把栈中的乘除结果算出来。
            elif arr[i] != '(':
                mulNum(deque,pre)
                deque.append(arr[i])
                i += 1
                pre = 0
            #如果是左括号(,就递归。
            else:
                bra = value(arr,i+1)
                pre = bra[0]
                i = bra[1] + 1
        #如果是右括号)或者结束了,就求出最终结果。
        mulNum(deque,pre)
        return [addNum(deque),i]
    #乘除法计算          
    def mulNum(deque,pre):
        if deque:
            last = deque.pop()
            if last == '+' or last == '-':
                deque.append(last)
            else:
                cur = int(deque.pop())
                pre = pre * cur if last == '*' else cur / pre
        deque.append(pre)
    #加减法计算
    def addNum(deque):
        res = 0
        sign = 1
        while deque:
            cur = deque.pop(0)
            if cur == '-':
                sign = -1
            elif cur == '+':
                sign = 1
            else:
                res += sign * int(cur)
        return res
    exp = '48*((70-65)-43)+8*1*3+5/5'
    getValue(exp)
                
    
    
  • 相关阅读:
    git常用指令 github版本回退 reset
    三门问题 概率论
    如何高效的学习高等数学
    数据库6 关系代数(relational algebra) 函数依赖(functional dependency)
    数据库5 索引 动态哈希(Dynamic Hashing)
    数据库4 3层结构(Three Level Architecture) DBA DML DDL DCL DQL
    梦想开始的地方
    java String字符串转对象实体类
    java 生成图片验证码
    java 对象之间相同属性进行赋值
  • 原文地址:https://www.cnblogs.com/Lee-yl/p/9959580.html
Copyright © 2011-2022 走看看