1. 程式人生 > >LeetCode 227. Basic Calculator II 解題報告【python】

LeetCode 227. Basic Calculator II 解題報告【python】

思路分析

該題是一個簡單的表示式求值問題,我們可以採用“算符優先法”來解決該問題。該演算法在嚴蔚敏的《資料結構C語言版》第三章有詳細描述。
該題中的每一個表示式都是由運算元和操作符組成,根據四則運演算法則中的“先算乘除,後算加減”原則,任意兩個相繼出現的操作符op1和op2之間的優先關係至多是下面的三種關係之一:
op1 < op2 表示op1的優先權低於op2
op1 = op2 表示op1的優先權等於op2
op1 > op2 表示op1的優先權高於op2

下表定義了算符之間的這種優先關係。

算符\算符 + - * /
+ > > < <
- > > < <
* > > > >
/ > > > >

下面舉一個例子來說明優先順序表的意義:比如有一個表示式 3 +10 *8, 這裡有兩個運算子 + 和 *,而且+在*之前,那麼就找到+行*列(上表紅色字型),就能知道這兩個符號的優先順序關係了。

為了演算法簡單,我們引入運算子#, 該運算子優先順序低於其他所有運算子,但是和自己的優先順序比較是=

下面給出完整的運算子優先關係表。

. + - * / #
+ > > < < >
- > > < < >
* > > > > >
/ > > > > >
# < < < < =

為了實現算符優先演算法,可以使用兩個棧,一個稱作stackNum,用來存放運算元,另一個稱作stackOp用來存放操作符。
演算法的基本思想是:
1. 首先置運算元棧stackNum為空棧,#作為運算子棧stackOp的棧低.
2. 依次讀入表示式中每個字元,若是運算元,則進stackNum,若是運算子,則和stackOp棧的棧頂運算子比較優先權後做相應操作。記stackOp棧頂的操作符為op1, 讀入的操作符為op2, 這時候會出現三種情況:
1)op1 > op2,則從stackOp彈出棧頂運算子,並從stackNum中彈出兩個運算元b, a,根據運算元a,b和操作符c, 計算出新的運算元c,將c壓入stackNum
2) op1 < op2,直接將當前讀入的操作符op2壓入stackOp
3) op1 = op2,這種情況只出現在op1和op2都是#,此時直接將stackOp中的#彈出即可,同時演算法結束

程式碼(Python描述)

class Solution(object):

    def calculate(self, s):
        """
        :type s: str
        :rtype: int
        """
        checkFun = lambda x: x if x.isdigit() or x in ('+', '-', '*', '/') else None
        exp = filter(checkFun, re.split(r"(\D)", s))
        precedeTable = {'++' : '>', '+-' : '>', '+*' : '<', '+/' : '<', '+#' : '>',\
                        '-+' : '>', '--' : '>', '-*' : '<', '-/' : '<', '-#' : '>',\
                        '*+' : '>', '*-' : '>', '**' : '>', '*/' : '>', '*#' : '>',\
                        '/+' : '>', '/-' : '>', '/*' : '>', '//' : '>', '/#' : '>',\
                        '#+' : '<', '#-' : '<', '#*' : '<', '#/' : '<', '##' : '='}
        stackOp = ['#']
        stackNum = []
        exp.append('#')
        i = 0
        while i < len(exp):
            e = exp[i]
            if e.isdigit():
                stackNum.append(int(e))
                i += 1
            else:
                if precedeTable[stackOp[-1] + e] == '<':
                    stackOp.append(e)
                    i += 1
                elif precedeTable[stackOp[-1] + e] == '>':
                    b = stackNum.pop()
                    a = stackNum.pop()
                    op = stackOp.pop()
                    if op == '+':
                        stackNum.append(a + b)
                    elif op == '-':
                        stackNum.append(a - b)
                    elif op == '*':
                        stackNum.append(a * b)
                    else:
                        stackNum.append(a / b)
                else:
                    stackOp.pop()
                    i += 1
        return stackNum[0]