题目:
序列化二叉树的一种方法是使用前序遍历。当我们遇到一个非空节点时,我们可以记录下这个节点的值。如果它是一个空节点,我们可以使用一个标记值记录,例如 #。
例如,上面的二叉树可以被序列化为字符串 "9,3,4,#,#,1,#,#,2,#,6,#,#",其中 # 代表一个空节点。
给定一串以逗号分隔的序列,验证它是否是正确的二叉树的前序序列化。编写一个在不重构树的条件下的可行算法。
每个以逗号分隔的字符或为一个整数或为一个表示 null 指针的 '#' 。
你可以认为输入格式总是有效的,例如它永远不会包含两个连续的逗号,比如 "1,,3" 。
来源:
解题思路1:栈
读完题后有点懵,仔细看了看题中的例子发现,#都是叶子节点,数字都是非叶节点。
确定思路如下:#出栈,数字入栈
定义一个栈,存储数字节点的孩子个数,数字节点必须有2个孩子。循环所有节点:
- 当节点是#号时,若栈为空则结束,否则给栈顶元素增加一个孩子;
- 当节点是数字时,若栈为空则直接入栈,否则给栈顶元素增加一个孩子后再入栈;
- 当栈顶节点已满足2个孩子时,出栈直到空或栈顶节点不够2个孩子。
当栈为空并且后面没有节点时,返回true,其他false。
代码如下(有点混乱):
class Solution {
public:
bool isValidSerialization(string preorder) {
stack<int> st;
int i = 0;
while (i < preorder.size()) {
char ch = preorder[i];
while (i < preorder.size() && preorder[i] != ',') i++;
i++;
if (ch == '#') {
if (st.empty()) break;
// top++
int t = st.top();
st.pop();
st.push(t+1);
} else {
// top++
if (!st.empty()) {
int t = st.top();
st.pop();
st.push(t+1);
}
st.push(0);
}
bool end = false;
while (st.top() == 2) {
st.pop();
if (st.empty()) {
end = true;
break;
}
}
if (end) break;
}
return st.empty() && i >= preorder.size();
}
};
解题思路2:利用节点性质
每个非叶节点必然有2个孩子,那么一定满足:叶子节点一定比非叶节点多1个。在此题中,则为#节点比数字节点多1个。
根据这个性质写代码就简单了:定义计数cnt=1,当#时--,数字时++,计数0时退出,退出后判断后续还有没有节点。
int isValidSerialization(char * preorder){
int cnt = 1;
char *p = preorder;
while (*p != 0) {
if (*p == '#') {
cnt--;
} else {
cnt++;
}
while (*p != 0 && *p != ',') p++;
if (*p == ',') p++;
if (cnt == 0) break;
}
return cnt == 0 && *p == 0;
}