[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; } };
参考资料:
https://discuss.leetcode.com/topic/64389/easy-and-concise-5-lines-python-java-solution
https://discuss.leetcode.com/topic/64409/very-easy-1-pass-stack-solution-in-java-no-string-concat/2