[LeetCode] Ternary Expression Parser 三元表示式解析器
Given a string representing arbitrarily nested ternary expressions, calculate the result of the expression. You can always assume that the given expression is valid and only consists of digits 0-9
, ?
, :
, T
and F
(T
and F
represent True and False respectively).
Note:
- The length of the given string is ≤ 10000.
- Each number will contain only one digit.
- The conditional expressions group right-to-left (as usual in most languages).
- The condition will always be either
T
orF
. That is, the condition will never be a digit. - The result of the expression will always evaluate to either a digit
0-9
,T
orF
.
Example 1:
Input: "T?2:3" Output: "2" Explanation: If true, then result is 2; otherwise result is 3.
Example 2:
Input: "F?1:T?4:5" Output: "4" Explanation: The conditional expressions group right-to-left. Using parenthesis, it is read/evaluated as: "(F ? 1 : (T ? 4 : 5))" "(F ? 1 : (T ? 4 : 5))" -> "(F ? 1 : 4)" or -> "(T ? 4 : 5)" -> "4" -> "4"
Example 3:
Input: "T?T?F:5:3" Output: "F" Explanation: The conditional expressions group right-to-left. Using parenthesis, it is read/evaluated as: "(T ? (T ? F : 5) : 3)" "(T ? (T ? F : 5) : 3)" -> "(T ? F : 3)" or -> "(T ? F : 5)" -> "F" -> "F"
這道題讓我們解析一個三元表示式,我們通過分析題目中的例子可以知道,如果有多個三元表示式巢狀的情況出現,那麼我們的做法是從右邊開始找到第一個問號,然後先處理這個三元表示式,然後再一步一步向左推,這也符合程式是從右向左執行的特點。那麼我最先想到的方法是用用一個stack來記錄所有問號的位置,然後根據此問號的位置,取出當前的三元表示式,呼叫一個eval函式來分析得到結果,能這樣做的原因是題目中限定了三元表示式每一部分只有一個字元,而且需要分析的三元表示式是合法的,然後我們把分析後的結果和前後兩段拼接成一個新的字串,繼續處理之前一個問號,這樣當所有問號處理完成後,所剩的一個字元就是答案,參見程式碼如下:
解法一:
class Solution { public: string parseTernary(string expression) { string res = expression; stack<int> s; for (int i = 0; i < expression.size(); ++i) { if (expression[i] == '?') s.push(i); } while (!s.empty()) { int t = s.top(); s.pop(); res = res.substr(0, t - 1) + eval(res.substr(t - 1, 5)) + res.substr(t + 4); } return res; } string eval(string str) { if (str.size() != 5) return ""; return str[0] == 'T' ? str.substr(2, 1) : str.substr(4); } };
下面這種方法也是利用棧stack的思想,但是不同之處在於不是存問號的位置,而是存所有的字元,將原陣列從後往前遍歷,將遍歷到的字元都壓入棧中,我們檢測如果棧首元素是問號,說明我們當前遍歷到的字元是T或F,然後我們移除問號,再取出第一部分,再移除冒號,再取出第二部分,我們根據當前字元來判斷是放哪一部分進棧,這樣遍歷完成後,所有問號都處理完了,剩下的棧頂元素即為所求:
解法二:
class Solution { public: string parseTernary(string expression) { stack<char> s; for (int i = expression.size() - 1; i >= 0; --i) { char c = expression[i]; if (!s.empty() && s.top() == '?') { s.pop(); char first = s.top(); s.pop(); s.pop(); char second = s.top(); s.pop(); s.push(c == 'T' ? first : second); } else { s.push(c); } } return string(1, s.top()); } };
下面這種方法更加簡潔,沒有用到棧,但是用到了STL的內建函式find_last_of,用於查詢字串中最後一個目前字串出現的位置,這裡我們找最後一個問號出現的位置,剛好就是最右邊的問號,我們進行跟解法一類似的處理,拼接字串,迴圈處理,參見程式碼如下:
解法三:
class Solution { public: string parseTernary(string expression) { string res = expression; while (res.size() > 1) { int i = res.find_last_of("?"); res = res.substr(0, i - 1) + string(1, res[i - 1] == 'T' ? res[i + 1] : res[i + 3]) + res.substr(i + 4); } return res; } };
參考資料: