Hi,大家好。今天又是一個精神滿滿(沒睡醒)的週一,這周我們給大家帶來一道難度中等的題目——逆波蘭表達式的求解。
在開始之前,我們先了解一下逆波蘭表達式:
逆波蘭表達式又叫做後綴表達式。逆波蘭表示法是波蘭邏輯學家J・盧卡西維茲(J・ Lukasewicz)於1929年首先提出的一種表達式的表示方法。後來,人們就把用這種表示法寫出的表達式稱作“逆波蘭表達式”。逆波蘭表達式把運算量寫在前面,把算符寫在後面。(來自百度百科)
逆波蘭表達式即將兩個運算量寫在運算符前面,例如我們最常見的1 + 1
,寫成逆波蘭表達式爲1 1 +
。
描述
根據逆波蘭表示法,求表達式的值。
有效的運算符包括+
, -
, *
, /
。每個運算對象可以是整數,也可以是另一個逆波蘭表達式。
說明:
整數除法只保留整數部分。
給定逆波蘭表達式總是有效的。換句話說,表達式總會得出有效數值且不存在除數爲0
的情況。
逆波蘭表達式:
逆波蘭表達式是一種後綴表達式,所謂後綴就是指算符寫在後面。
平常使用的算式則是一種中綴表達式,如 ( 1 + 2 ) * ( 3 + 4 )
。
該算式的逆波蘭表達式寫法爲 ( ( 1 2 + ) ( 3 4 + ) * )
。
逆波蘭表達式主要有以下兩個優點:
去掉括號後表達式無歧義,上式即便寫成1 2 + 3 4 + *
也可以依據次序計算出正確結果。
適合用棧操作運算:遇到數字則入棧;遇到算符則取出棧頂兩個數字進行計算,並將結果壓入棧中。
示例
示例1
輸入:
["2", "1", "+", "3", "*"]
輸出:
9
解釋: 該算式轉化爲常見的中綴算術表達式爲:((2 + 1) * 3) = 9
示例2
輸入:
["4", "13", "5", "/", "+"]
輸出:
6
解釋: 該算式轉化爲常見的中綴算術表達式爲:(4 + (13 / 5)) = 6
示例3
輸入:
["10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+"]
輸出:
22
解釋:
該算式轉化爲常見的中綴算術表達式爲:
((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22
解法
因爲題中聲明瞭作爲參數傳入的逆波蘭表達式將是一個有效的表達式,所以在我們的解法中便沒有再次進行校驗,若是實際使用的場景還需要額外的校驗處理。正如上文中所說的,我們將藉助一個棧來存儲得到的計算結果:
public int EvalRPN(string[] tokens)
{
Stack<int> stack = new Stack<int>();
foreach (string token in tokens)
{
switch (token)
{
case "+":
case "-":
case "*":
case "/":
Calculate(stack, token);
break;
default:
stack.Push(int.Parse(token));
break;
}
}
return stack.Pop();
}
在EvalRPN
方法中,我們主要做了三件事:
- 噹噹前
token
爲運算符時,調用Calculate
方法計算; - 當
token
不爲運算符時,將其轉爲int
類型並壓入到棧中; - 在結束時將結果從棧中取出。
下面讓我們看看Calculate
方法:
void Calculate(Stack<int> stack, string op)
{
int num2 = stack.Pop();
int num1 = stack.Pop();
int ret = 0;
switch (op)
{
case "+":
ret = num1 + num2;
break;
case "-":
ret = num1 - num2;
break;
case "*":
ret = num1 * num2;
break;
case "/":
ret = num1 / num2;
break;
default:
break;
}
stack.Push(ret);
}
在Calculate
方法中,我們先將需要參與運算的兩個數值從棧中取出。需要注意的是,棧是一種先進後出的結果,所以我們在使用時先取出的數值作爲運算的第二個運算量(在減法中需要區分減數與被減數,除法中需要區分除數與被除數)。
在取出兩個運算量後,只需要按照傳入的運算符進行對應的運算得到結果並重新壓回到棧中即可。
結束語
對於逆波蘭表達式的求解,我們只給出了使用棧求解的解法,大家也可以去探索一下更多的解法。
今天的內容就到這裏啦,我們下週再見👋~
歡迎大家關注我的公衆號“風紙”,或是掃下面的二維碼關注👇