問題描述:
序列化二叉樹的一種方法是使用前序遍歷。當我們遇到一個非空節點時,我們可以記錄下這個節點的值。如果它是一個空節點,我們可以使用一個標記值記錄,例如 #
。
_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
}
參考: