1. 程式人生 > >[LeetCode] Construct Binary Tree from String 從字串建立二叉樹

[LeetCode] Construct Binary Tree from String 從字串建立二叉樹

You need to construct a binary tree from a string consisting of parenthesis and integers.

The whole input represents a binary tree. It contains an integer followed by zero, one or two pairs of parenthesis. The integer represents the root's value and a pair of parenthesis contains a child binary tree with the same structure.

You always start to construct the left child node of the parent first if it exists.

Example:

Input: "4(2(3)(1))(6(5))"
Output: return the tree root node representing the following tree:

       4
     /   \
    2     6
   / \   / 
  3   1 5   

Note:

  1. There will only be '('')''-' and '0'
     ~ '9' in the input string.
  2. An empty tree is represented by "" instead of "()".

這道題讓我們根據一個字串來建立一個二叉樹,其中結點與其左右子樹是用括號隔開,每個括號中又是數字後面的跟括號的模式,這種模型就很有遞迴的感覺,所以我們當然可以使用遞迴來做。首先我們要做的是先找出根結點值,我們找第一個左括號的位置,如果找不到,說明當前字串都是數字,直接轉化為整型,然後新建結點返回即可。否則的話從當前位置開始遍歷,因為當前位置是一個左括號,我們的目標是找到與之對應的右括號的位置,但是由於中間還會遇到左右括號,所以我們需要用一個變數cnt來記錄左括號的個數,如果遇到左括號,cnt自增1,如果遇到右括號,cnt自減1,這樣當某個時刻cnt為0的時候,我們就確定了一個完整的子樹的位置,那麼問題來了,這個子樹到底是左子樹還是右子樹呢,我們需要一個輔助變數start,當最開始找到第一個左括號的位置時,將start賦值為該位置,那麼當cnt為0時,如果start還是原來的位置,說明這個是左子樹,我們對其呼叫遞迴函式,注意此時更新start的位置,這樣就能區分左右子樹了,參見程式碼如下:

解法一:

class Solution {
public:
    TreeNode* str2tree(string s) {
        if (s.empty()) return NULL;
        auto found = s.find('(');
        int val = (found == string::npos) ? stoi(s) : stoi(s.substr(0, found));
        TreeNode *cur = new TreeNode(val);
        if (found == string::npos) return cur;
        int start = found, cnt = 0;
        for (int i = start; i < s.size(); ++i) {
            if (s[i] == '(') ++cnt;
            else if (s[i] == ')') --cnt;
            if (cnt == 0 && start == found) {
                cur->left = str2tree(s.substr(start + 1, i - start - 1));
                start = i + 1;
            } else if (cnt == 0) {
                cur->right = str2tree(s.substr(start + 1, i - start - 1));
            }
        }
        return cur;
    }
};

下面這種解法使用迭代來做的,藉助棧stack來實現。遍歷字串s,用變數j記錄當前位置i,然後看當前遍歷到的字元是什麼,如果遇到的是左括號,什麼也不做繼續遍歷;如果遇到的是數字或者負號,那麼我們將連續的數字都找出來,然後轉為整型並新建結點,此時我們看stack中是否有結點,如果有的話,當前結點就是棧頂結點的子結點,如果棧頂結點沒有左子結點,那麼此結點就是其左子結點,反之則為其右子結點。之後要將此結點壓入棧中。如果我們遍歷到的是右括號,說明棧頂元素的子結點已經處理完了,將其移除棧,參見程式碼如下:

解法二:

class Solution {
public:
    TreeNode* str2tree(string s) {
        if (s.empty()) return NULL;
        stack<TreeNode*> st;
        for (int i = 0; i < s.size(); ++i) {
            int j = i;
            if (s[i] == ')') st.pop();
            else if ((s[i] >= '0' && s[i] <= '9') || s[i] == '-') {
                while (i + 1 < s.size() && s[i + 1] >= '0' && s[i + 1] <= '9') ++i;
                TreeNode *cur = new TreeNode(stoi(s.substr(j, i - j + 1)));
                if (!st.empty()) {
                    TreeNode *t = st.top();
                    if (!t->left) t->left = cur;
                    else t->right = cur;
                }
                st.push(cur);
            }
        }
        return st.top();
    }
};

參考資料: