LeetCode 227. Basic Calculator II 解題報告【python】
阿新 • • 發佈:2019-02-10
思路分析
- 該題是一個簡單的表示式求值問題,我們可以採用“算符優先法”來解決該問題。該演算法在嚴蔚敏的《資料結構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]