LEETCOCE 224. Basic Calculator

Implement a basic calculator to evaluate a simple expression string.

The expression string may contain open ( and closing parentheses ), the plus + or minus sign -, non-negative integers and empty spaces .

意思是实现只有加减法的带空格的算术表达式。

1.用构造二叉树的方法

对于一个算式,找到最后一个被使用的运算符作为划分,以此运算符为界,递归计算左边的值,递归计算右边的值,然后以此运算符进行运算,即可得到结果.最后一个被使用的运算符是什么呢? 例如: 2+3*(4-1)-5/1 肯定先算括号里的, 然后算* / 法,最后才考虑+,-法 . 所以,先考虑+,-法,再考虑* / 法. 括号外的+-*/可能很多,所以确定一个原则,找整个算式中最右边+-,*/. 由于要找的是括号外的+-*/, 所以得想办法避免记录括号内的+-*/,所以设置了一个标志p,初始0 一旦遇到一个左括号, p+1, 这时候说明目前在括号内,不应该记录+-*/, 当遇到右括号,p-1,p恢复为0,这时候说明目前已经走出括号,可以记录+-*/ . 扫描完真个算时候,C1记录了最右边的括号外的+-号,C2记录了最右边的括号外的*/号. 如果c1<0,说明没扫描到括号外的+-号, 那么只能考虑*/号作为最后一个运算的运算符了. 把c1=c2,然后判断c1<0, 如果还<0, 说明括号外也没有*/号, 说明整个算式被括号包围起来了. 所以可以递归运算时忽略这对括号,即递归(x+1,y-1)的算式, 返回它的子树根.代码如下:

class Treenode:
    def __init__(self,x):
        self.val=x
        self.left=self.right=None
        
def calculate(s):
        """
        :type s: str
        :rtype: int
        """
        def buildTree(s):
            n=len(s)
            if n==1:return Treenode(s[0])
            k,p=-1,0
            for i in range(n):
                c=s[i]
                if c=='(':
                    p+=1
                elif c==')':
                    p-=1
                elif c in ('+','-'):
                    if p==0:k=i
            if k<0:return buildTree(s[1:-1])        
            root=Treenode(s[k])
            root.left=buildTree(s[:k])
            root.right=buildTree(s[k+1:])
            return root
        
        def f(root):
            if root.left==None:return int(root.val)
            l=f(root.left)
            r=f(root.right)
            if root.val=='+':return l+r
            return l-r
        
        t,i=[],0
        while i<len(s):
            c=s[i]
            if c in '()+-':
                t.append(c)
                i+=1
            elif c==' ':
                i+=1
            else:
                k=i
                while i<len(s) and s[i] in '0123456789':i+=1
                t.append(s[k:i])
        #print(t)
        root=buildTree(t)
        
        return f(root)

上述算法可以做个优化,不用真的构造二叉树再遍历,二个过程合二为一.代码如下:

def calculate(s):
        """
        :type s: str
        :rtype: int
        """
        def dp(s):
            n=len(s)
            if n==1:return int(s[0])
            p=0
            for i in range(n-1,-1,-1):
                c=s[i]
                if c=='(':
                    p+=1
                elif c==')':
                    p-=1
                elif c in ('+','-'):
                    if p==0:break
            else:return dp(s[1:-1])        
            l=dp(s[:i])
            r=dp(s[i+1:])
            if s[i]=='+':return l+r
            return l-r
        
        t,i=[],0
        while i<len(s):
            c=s[i]
            if c in '()+-':
                t.append(c)
                i+=1
            elif c==' ':
                i+=1
            else:
                k=i
                while i<len(s) and s[i] in '0123456789':i+=1
                t.append(s[k:i])
        #print(t)
        return dp(t)

2.逆波兰表达式

逆波兰表达式又称后缀表达式,运算符位于操作数之后.比如(3+4)×5-6的逆波兰表达式是“3 4 + 5 × 6 -”.生成逆波兰表达式的算法如下:从左至右扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素 op 栈顶元素),并将结果入栈;重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果.具体点:

  1. 初始化两个栈:运算符栈s1和储存中间结果的栈s2;
  2. 从左至右扫描中缀表达式;
  3. 遇到操作数时,将其压s2;
  4. 遇到运算符时,比较其与s1栈顶运算符的优先级:
    1. 如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
    2. 否则,若优先级比栈顶运算符的高,也将运算符压入s1;
    3. 否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈顶运算符相比较;
  5. 遇到括号时:
    1. 如果是左括号“(”,则直接压入s1;
    2. 如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃;
  6. 重复步骤2至5,直到表达式的最右边;
  7. 将s1中剩余的运算符依次弹出并压入s2;
  8. 依次弹出s2中的元素并输出,结果即为后缀表达式

def calculate(s):
        """
        :type s: str
        :rtype: int
        """

s1,s2,n,i=[],[],len(s),0
        while i<n:
            c=s[i]
            if c in '+-':
                while s1 and s1[-1]!='(':s2.append(s1.pop())
                s1.append(c)
                i+=1
            elif c=='(':
                s1.append(c)
                i+=1
            elif c==')':
               op=s1.pop()
               while op!='(':
                  s2.append(op)
                  op=s1.pop()
               i+=1
            elif c==' ':
                i+=1
            else:
                k=i
                while i<len(s) and s[i] in '0123456789':i+=1
                s2.append(s[k:i])
        while s1:s2.append(s1.pop())

stack=[]
        for c in s2:
            if c in '+-':
               r,l=stack.pop(),stack.pop()
               if c=='+':
                  stack.append(l+r)
               else:
                  stack.append(l-r)
            else:
               stack.append(int(c))
        return stack[-1]

3.其他方法

def calculate(s):
"""
:type s: str
:rtype: int
"""
sign,val,curr,stack = 1,0,0,[]
    for c in s:
            if c in '0123456789':
                curr = curr * 10 + int(c)
            elif c in '+-':
                val += sign * curr
                curr,sign = 0,int(c+'1')
            elif c == '(':
                stack.append(val)
                stack.append(sign)
                sign,val = 1,0
            elif c == ')':
                val += sign * curr
                curr = 0
                val *= stack.pop()
                val += stack.pop()
     if curr: val += curr * sign
     return val

PYTHON实现算术表达式构造二叉树的更多相关文章

  1. [Java]算术表达式组建二叉树,再由二叉树得到算式的后序和中序表达式

    Entry类: package com.hy; import java.io.BufferedReader; import java.io.IOException; import java.io.In ...

  2. python实现算术表达式的词法语法语义分析(编译原理应用)

    本学期编译原理的一个大作业,我的选题是算术表达式的词法语法语义分析,当时由于学得比较渣,只用了递归下降的方法进行了分析. 首先,用户输入算术表达式,其中算术表达式可以包含基本运算符,括号,数字,以及用 ...

  3. [Java]算术表达式求值之三(中序表达式转二叉树方案 支持小数)

    Entry类 这个类对表达式的合法性进行了粗筛: package com.hy; import java.io.BufferedReader; import java.io.IOException; ...

  4. Python运算符与表达式

    Python运算符包括赋值运算符.算术运算符.关系运算符.逻辑运算符.位运算符.成员运算符和身份运算符. 表达式是将不同类型的数据(常亮.变量.函数)用运算符按照一定得规则连接起来的式子. 算术运算符 ...

  5. poj3295解题报告(构造、算术表达式运算)

    POJ 3952,题目链接http://poj.org/problem?id=3295 题意: 输入由p.q.r.s.t.K.A.N.C.E共10个字母组成的逻辑表达式, 其中p.q.r.s.t的值为 ...

  6. LeetCode--105--从前序与中序遍历序列构造二叉树(python)

    根据一棵树的前序遍历与中序遍历构造二叉树. 注意:你可以假设树中没有重复的元素. 例如,给出 前序遍历 preorder = [3,9,20,15,7]中序遍历 inorder = [9,3,15,2 ...

  7. 【算法】E.W.Dijkstra算术表达式求值

    算术表达式求值 我们要学习的一个栈的用例同时也是展示泛型的应用的一个经典例子,就是用来计算算术表达式的值,例如 ( 1 + ( ( 2 + 3 ) * ( 4 * 5 ) ) ) 如果将4乘以5,把3 ...

  8. Project Euler 93:Arithmetic expressions 算术表达式

    Arithmetic expressions By using each of the digits from the set, {1, 2, 3, 4}, exactly once, and mak ...

  9. [Java]算术表达式求值之二(中序表达式转后序表达式方案,支持小数)

    Inlet类,入口类,这个类的主要用途是验证用户输入的算术表达式: package com.hy; import java.io.BufferedReader; import java.io.IOEx ...

随机推荐

  1. blogger添加代码高亮

    blogger(blogspot)自带的是没有代码高亮的,我们可以用下面的方法添加代码高亮. 首先我们打开blogger(blogspot)后台,然后点击主题背景-->修改html,然后在弹出的 ...

  2. Asp.net 按钮幕布遮盖效果实现方式

    Asp.net button按钮点击后想要实现幕布效果来等待服务器端执行完成,这种需求虽说看起来很简单,但真实做起来并不是那么简单,涉及了很多细节点,而对于深入理解asp.net button生命周期 ...

  3. Redhat更换yum源

    redhat 默认自带的 yum 源需要注册,才能更新,所以对于我们来说需要替换掉redhat的yum源.下文更换为网易的. 删除原有的yum rpm -qa|grep yum|xargs rpm - ...

  4. sourcetree,创建工作流报错:Fatal: Not a gitflow-enabled repo yet. Please run 'git flow init' first.-》解决办法

    1.打开项目下.git/config文件,或者如下图操作: 2.打开config文件以后,删除所有 [gitflow *条目并保存文件 3.关闭并重新打开sourcetree 4.仓库->Git ...

  5. js 变量作用域

    例子 <script> var a = "heh" function findLove(){ console.log(a); function findforyou() ...

  6. C++_day8_ 多重继承、钻石继承和虚继承

    1.继承的复习 1.1 类型转换 编译器认为访问范围缩小是安全的. 1.2 子类的构造与析构 子类中对基类构造函数初始化只能写在初始化表里,不能写在函数体中. 阻断继承. 1.3 子类的拷贝构造与拷贝 ...

  7. CART回归树

    决策树算法原理(ID3,C4.5) 决策树算法原理(CART分类树) 决策树的剪枝 CART回归树模型表达式: 其中,数据空间被划分为R1~Rm单元,每个单元有一个固定的输出值Cm.这样可以计算模型输 ...

  8. jquery清除某一结点下的子节点

    jquery清除某一结点下的子节点:这个情况多用于数据的加载中,如果当执行某一操作之后,想重新加载页面,但是又不想整个页面都重新加载,这个时候就可以使用该方法, case:   $("#ta ...

  9. 【原】git常见用法

    1.克隆 当前用户:git clone 192.165.53.15:/home/git/repo/Tegra/bsp/tx1_filesystem.git/ 非当前用户:git clone xxxxx ...

  10. Bubble sort of sorting algorithm

    Bubble sort,It's a relatively basic algorithm.The core implementation ideas are as follows: 1.Define ...