1. 程式人生 > >[LeetCode] Ternary Expression Parser 三元表示式解析器

[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 Frepresent True and False respectively).

Note:

  1. The length of the given string is ≤ 10000.
  2. Each number will contain only one digit.
  3. The conditional expressions group right-to-left (as usual in most languages).
  4. The condition will always be either T or F. That is, the condition will never be a digit.
  5. The result of the expression will always evaluate to either a digit 0-9T or F.

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;
    }
};

參考資料: