驗證二叉樹的前序序列化
前言
最近自己的學長面試的時候遇到這一道題了,然後把這道題出給了我。我的第一想法是根據前序遍歷建立一個樹結構,然後根據能否建立樹來判斷。但是題目要求不能重建樹,所以自己確實不會做。在網上看了別人的解答才恍然大悟!這裏總結一下大神們的解法。
關於istringstream
首先我們肯定要用istringstream來操作字符串,C++裏面沒有像Java那樣有字符串的split函數(可以直接分割任意字符串);在C++裏我們只能用getline這個函數從用戶處獲得字符,將字符串流的內容都存到一個vector數組中。我們可以先看一個簡單的例子:
int main()
{
istringstream in("a,b,c,d,e,d,f" );
string t = "";
while (getline(in, t, ','))
{
cout << t;
Sleep(100);
}
system("pause");
return 0;
}
istringstream類用於執行C++風格的串流的輸入操作。
ostringstream類用於執行C風格的串流的輸出操作。
strstream類同時可以支持C風格的串流的輸入輸出操作。
這個函數是從string對象中讀取字符到in中,然後在執行while (getline(in, t, ‘,‘))
abcdedf
解法一
通過仔細觀察我們可以發現兩個規律:1.數字的個數總是比#號少一個;2.最後一個一定是#號。
所以我們可以根據這兩個規律,將最後一個字符“#”單獨進行考慮,那麽此時數字的個數和#的個數應該相同。所以可以初始化一個計數器專門記錄數字的個數,當遇到數字則計數器+1,遇到#號-1;這樣遍歷到除了最後一個字符,則一定會有計數器=0!。所以最後遍歷完的判斷就是計數器是否等於0與最後一個字符是不是#。
當然還有一些小細節要處理,比如“#,9,3,4,#”與“9,3,#,#,#,1”這兩個錯誤案例,根節點首先不能為#,同時要確保在[0,i]這個範圍內#的個數是不大於數字的個數的。所以可以通過在循環中判斷是否會有計數器小於0的情況,代碼如下:
class Solution {
public:
bool isValidSerialization(string preorder) {
istringstream in(preorder);
string t="";
int cnt=0;
while(getline(in,t,','))
v.push_back(t);
for(int i=0;i<v.size()-1;i++)
{
if(v[i]=="#")
{
if(cnt==0)
return false;
cnt--;
}
else
cnt++;
}
return cnt==0 && v.back()=="#";
}
private:
vector<string> v;
};
解法二
解法二是邊解析邊判斷,遇到不合題意的情況直接返回false,而不用全部解析完再來驗證是否合法,提高了運算的效率。
class Solution {
public:
bool isValidSerialization(string preorder) {
istringstream in(preorder);
string t = "";
int degree = 1;
bool degree_is_zero = false;;
while (getline(in, t, ',')) {
if (degree_is_zero) return false;
if (t == "#") {
if (--degree == 0) degree_is_zero = true;
} else ++degree;
}
return degree == 0;
}
};
解法三
這種解法就更加巧妙了,連字符串解析都不需要了,用一個變量capacity來記錄能容忍"#"的個數,跟上面解法中的degree一個作用,然後我們給preorder末尾加一個逗號,這樣可以處理末尾的"#"。我們遍歷preorder字符串,如果遇到了非逗號的字符,直接跳過,否則的話capacity自減1,如果此時capacity小於0了,直接返回true。此時再判斷逗號前面的字符是否為"#",如果不是的話,capacity自增2。這種設計非常巧妙,如果逗號前面是"#",我們capacity自減1沒問題,因為容忍了一個"#";如果前面是數字,那麽先自減的1,可以看作是初始化的1被減了,然後再自增2,因為每多一個數字,可以多容忍兩個"#",最後還是要判斷capacity是否為0,跟上面的解法一樣,我們要補齊"#"的個數,少了也是不對的,參見代碼如下:
class Solution {
public:
bool isValidSerialization(string preorder) {
int capacity = 1;
preorder += ",";
for (int i = 0; i < preorder.size(); ++i) {
if (preorder[i] != ',') continue;
if (--capacity < 0) return false;
if (preorder[i - 1] != '#') capacity += 2;
}
return capacity == 0;
}
};
驗證二叉樹的前序序列化