【leetcode】驗證二叉樹的前序序列化 C++/Go(棧/遞歸)

問題描述:

序列化二叉樹的一種方法是使用前序遍歷。當我們遇到一個非空節點時,我們可以記錄下這個節點的值。如果它是一個空節點,我們可以使用一個標記值記錄,例如 #

     _9_
    /   \
   3     2
  / \   / \
 4   1  #  6
/ \ / \   / \
# # # #   # #

例如,上面的二叉樹可以被序列化為字符串 "9,3,4,#,#,1,#,#,2,#,6,#,#",其中 # 代表一個空節點。

給定一串以逗號分隔的序列,驗證它是否是正確的二叉樹的前序序列化。編寫一個在不重構樹的條件下的可行算法。

每個以逗號分隔的字符或為一個整數或為一個表示 null 指針的 '#'

你可以認為輸入格式總是有效的,例如它永遠不會包含兩個連續的逗號,比如 "1,,3"

示例 1:

輸入: "9,3,4,#,#,1,#,#,2,#,6,#,#"
輸出: true

示例 2:

輸入: "1,#"
輸出: false

示例 3:

輸入: "9,#,#,1"
輸出: false

遞歸思想

前序遍歷其實就是深度優點遍歷,向一直往左節點向下走,知道走不動了再走右節點。那么我們可以考慮下面這種基本的情況:

基本情況

將兩個葉子去掉之后,可以消除0節點下面的所有子樹,那么就相當于我們可以刪除0以下的子樹。所以,這個時候,我們刪除兩個葉子節點,并且將0節點也設置為葉子節點,那么,有如下的轉換:

刪除子樹

我們注意到,當我們不斷的這樣刪除子樹的時候,節點不斷減少,只要是滿足二叉樹的前序遍歷的序列,最終都會變成下面這種情況

最終情況

而假如最終情況不是上面這種情況的,就不滿足二叉樹的前序遍歷。

例如:

字符串"1,#"的二叉樹表示如下,就不能夠消除

不符合的情況

代碼實現分析:

要編寫這個迭代遍歷的過程,使用棧思想比較容易實現,就是當遇到后面兩個都是"#"的時候("#"符號我們使用-1表示),我們可以刪除棧頂的3個元素,然后將一個“#”(也就是-1)壓入棧頂。不斷的循環這個操作,直到結尾。

C++實現:

class Solution {
public:
    bool isValidSerialization(string preorder) {
        int n = preorder.length();
        vector<int> stk;
        int num = 0;
        for(int i = 0;i < n;++i){
            if(isdigit(preorder[i])){
                num = num * 10 + (preorder[i] - '0');
                // 結尾情況也需要將數字入棧
                if(i == n -1) stk.push_back(num);
            }
            else if(preorder[i] == ',' && preorder[i-1] != '#'){
                stk.push_back(num);
                num = 0;
            }
            else if(preorder[i] == '#'){
                stk.push_back(-1);
                int len = stk.size();
                while(len >= 3 && stk[len-1] == -1 && stk[len-2] == -1){
                    stk.pop_back();
                    stk.pop_back();
                    stk.back() = -1;
                    len = stk.size();
                }
                // 提前出現最終結果,錯誤
                if(stk.size() == 1 && stk[0] == -1 && i != n-1){
                    return false;
                }
            }
        }
        // 判斷最終情況
        if(stk.size() == 1 && stk[0] == -1) return true;
        return false;
    }
};

Go實現:

func isValidSerialization(preorder string) bool {
    n := len(preorder)
    stk := make([]int,0)
    num := 0
    
    for i := 0; i < n; i++ {
        isdigit := (preorder[i] >= '0' && preorder[i] <= '9')
        if isdigit {
            num = num * 10 + int(preorder[i]-'0')
            if i == n - 1 {// 結尾是數字的情況
                stk = append(stk,num)
            }
        } else if preorder[i] == '#' {
            stk = append(stk,-1)
            snum := len(stk)
            for snum >= 3 && stk[snum-1] == -1 && stk[snum-2] == -1{
                stk = stk[0:snum-3]
                stk = append(stk,-1)
                snum = len(stk)
            }
            // 這里提前出現了最終的情況,也是錯誤的
            if len(stk) == 1 && stk[0] == -1 && i != n-1 {
                return false
            }
        } else if preorder[i] == ',' && preorder[i-1] != '#' {
            stk = append(stk,num)
            num = 0
        } 
    }
    // 判斷是否符合最終情況
    if len(stk) == 1 && stk[0] == -1 {
        return true
    }
    return false
}

參考:

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容