「@Author:Runsen」python
❝編程的本質來源於算法,而算法的本質來源於數學,編程只不過將數學題進行代碼化。「---- Runsen」git
❞
算法,一門既不容易入門,也不容易精通的學問。github
這是Leetcode第20題,也是一道單調棧的簡單題。面試
給定一個只包括'(',')','{','}','[',']'
的字符串,判斷字符串是否有效。正則表達式
有效字符串需知足:算法
輸入: "{[]}"
輸出: true
express
單調棧關鍵在於如何入棧和出棧。編程
用棧保存爲匹配的左括號,從左到右一次掃描字符串,當掃描到左括號時,則將其壓入棧中;當掃描到右括號時,從棧頂取出一個左括號,若是能匹配上,則繼續掃描剩下的字符串。若是掃描過程當中,遇到不能配對的右括號,或者棧中沒有數據,則說明爲非法格式。app
當全部的括號都掃描完成以後,若是棧爲空,則說明字符串爲合法格式;不然,說明未匹配的左括號爲非法格式。ide
def isValid(s):
"""
:type s: str
:rtype: bool
"""
stack = []
paren_map ={')':'(',']':'[','}':'{'}
for c in s:
if c not in paren_map:
stack.append(c)
elif not stack or paren_map[c] !=stack.pop():
return False
return not stack
s = input('輸入括號字符:')
print(isValid(s))
在此題中,也能夠利用python種的replace函數將成對的可匹配括號用空字符代替 ,以後依次進行 ,如果有效的括號 ,必然通過有限次循環後 ,字符串爲空 ,則最後判斷字符串是否爲空便可。思路簡單,實現也很容易:
def isValid(s):
"""
:type s: str
:rtype: bool
"""
n = len(s)
if n == 0: return True
while '()' in s or '{}' in s or '[]' in s:
s = s.replace('{}','').replace('[]','').replace('()Val','')
return s == ''
首先,咱們來看一下數學表達式的三種形式:前綴表達式,中綴表達式,後綴表達式。
中綴表達式(Infix Expression)就是咱們平時經常使用的書寫方式,帶有括號。
前綴表達式(Prefix Expression)要求運算符出如今運算數字的前面。
後綴表達式(Postfix Expression)要求運算符出如今運算數字的後面,通常這兩種表達式不出現括號。後綴表達式,又稱逆波蘭式。
數學表達式的三種形式示例以下:
中綴表達式 | 前綴表達式 | 後綴表達式 |
---|---|---|
A + B * C + D | + + A * B C D | A B C * + D + |
(A + B) * (C + D) | * + A B + C D | A B + C D + * |
A * B + C * D | + * A B * C D | A B * C D * + |
A + B + C + D | + + + A B C D | A B + C + D + |
中綴表達式操做符是以中綴形式處於操做數的中間(例:3 + 4),中綴表達式是人們經常使用的算術表示方法。與前綴表達式(例:+ 1 2)或後綴表達式(例:1 2 +)相比,中綴表達式不容易被計算機解析,但仍被許多程序語言使用,由於它符合人們的廣泛用法。
下面問題轉爲爲:如何利用棧實現中綴表達式求值,好比:34+13*9+44-12/3=191
思路:利用兩個棧,其中一個用來保存操做數,另外一個用來保存運算符。
咱們從左向右遍歷表達式,當遇到數字,咱們就直接壓入操做數棧;當遇到運算符,就與運算符棧的棧頂元素進行比較。
若比運算符棧頂元素優先級高,就將當前運算符壓入棧,若比運算符棧頂元素的優先級低或者相同,從運算符棧中取出棧頂運算符,從操做數棧頂取出2個操做數,而後進行計算,把計算完的結果壓入操做數棧,繼續比較。
def infix_evaluator(infix_expression : str) -> int :
'''這是中綴表達式求值的函數
:參數 infix_expression:中綴表達式 須要用空格進行隔開
'''
token_list = infix_expression.split()
print(token_list)
# 運算符優先級字典
pre_dict = {'*':3,'/':3,'+':2,'-':2, '(':1}
# 運算符棧
operator_stack = []
# 操做數棧
operand_stack = []
for token in token_list:
# 數字進操做數棧
print(token)
# 10或者-10的狀況
if token.isdecimal() or token[1:].isdecimal():
operand_stack.append(int(token))
# 左括號進運算符棧
elif token == '(':
operator_stack.append(token)
# 碰到右括號,就要把棧頂的左括號上面的運算符都彈出求值
elif token == ')':
top = operator_stack.pop()
while top != '(':
# 每彈出一個運算符,就要彈出兩個操做數來求值
# 注意彈出操做數的順序是反着的,先彈出的數是op2
op2 = operand_stack.pop()
op1 = operand_stack.pop()
# 求出的值要壓回操做數棧
# 這裏用到的函數get_value在下面有定義
operand_stack.append(get_value(top,op1,op2))
# 彈出下一個棧頂運算符
top = operator_stack.pop()
# 碰到運算符,就要把棧頂優先級不低於它的都彈出求值
elif token in '+-*/':
while operator_stack and pre_dict[operator_stack[-1]] >= pre_dict[token]:
top = operator_stack.pop()
op2 = operand_stack.pop()
op1 = operand_stack.pop()
operand_stack.append(get_value(top,op1,op2))
# 別忘了最後讓當前運算符進棧
operator_stack.append(token)
# 表達式遍歷完成後,棧裏剩下的操做符也都要求值
while operator_stack:
top = operator_stack.pop()
op2 = operand_stack.pop()
op1 = operand_stack.pop()
operand_stack.append(get_value(top,op1,op2))
# 最後棧裏只剩下一個數字,這個數字就是整個表達式最終的結果
print(operand_stack)
print(operator_stack)
return operand_stack[0]
def get_value(operator : str, op1 : int, op2 : int):
'''這是四則運算函數
:參數 operator:運算符
:參數 op1:左邊的操做數
:參數 op2:右邊的操做數
'''
if operator == '+':
return op1 + op2
elif operator == '-':
return op1 - op2
elif operator == '*':
return op1 * op2
elif operator == '/':
return op1 / op2
# 用一個例子試試,得出告終果 17.0
print(infix_evaluator('9 + ( 3 - 1 * 2 ) * 3 + 10 / 2'))
17.0
上述程序只是使用四則運算表達式進行學習計算,可是輸入須要加空格進行分隔,好比9 + ( 3 - 1 * 2 ) * 3 + 10 / 2
分隔爲['9', '+', '(', '3', '-', '1', '*', '2', ')', '*', '3', '+', '10', '/', '2']
。
後來嘗將9+(3-1*2)*3+10/2
分隔爲['9', '+', '(', '3', '-', '1', '*', '2', ')', '*', '3', '+', '10', '/', '2']
。
後來想到了正則表達式1-9]\d*|[\+\-\*\/\(\)]
。
import re
s = '9+(3-1*2)*3+10/2'
print(re.findall('[1-9]\d*|[\+\-\*\/\(\)]',s))
['9', '+', '(', '3', '-', '1', '*', '2', ')', '*', '3', '+', '10', '/', '2']
所以利用棧實現中綴表達式求值中等偏難算法題基本完成。
❝本文已收錄 GitHub,傳送門~[1] ,裏面更有大廠面試完整考點,歡迎 Star。
❞
傳送門~:https://github.com/MaoliRUNsen/runsenlearnpy100
- END -