PYTHON實現算術表達式構造二叉樹


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM