题目:
思路:
这道题是我今天目前碰到最有意思的题,首先思考只有前序遍历是无法完全确立重建二叉树的
在无法确立二叉树的情况下,得想想二叉树的其他性质
利用性质:空节点视为叶节点,根据性质叶节点数目比非叶节点数目多1来判断。
我们可以定义一个概念,叫做槽位,二叉树中任意一个节点或者空孩子节点都要占据一个槽位。二叉树的建立也伴随着槽位数量的变化。开始时只有一个槽位,如果根节点是空节点,就只消耗掉一个槽位,如果根节点不是空节点,除了消耗一个槽位,还要为孩子节点增加两个新的槽位。之后的节点也是同理。
有了上面的讨论,方法就很简单了。依次遍历前序序列化,根据节点是否为空,按照规则消耗/增加槽位。如果最后可以将所有的槽位消耗完,那么这个前序序列化就是合法的。
开始时只有一个可用槽位。
空节点和非空节点都消耗一个槽位。
空节点不增加槽位,非空节点增加两个槽位。
算法实现:
- 初始化可用槽位为 1:slots = 1。
- 遍历前序序列化字符串,每遍历到逗号字符:
- 空节点和非空节点都消耗一个槽位:slots = slot - 1。
- 如果当前可用槽位是负数,那么这个先序序列就是非法的,返回 False。
- 非空节点(即逗号字符前不是 #),新增两个可用槽位:slots = slots + 2`。
- 最后一个节点需要单独处理,因为最后一个节点后面是没有逗号的。
- 如果可用槽位全部被消耗完,那么该前序序列化就是合法的:返回 slots == 0。
代码:
class Solution {
public:
bool isValidSerialization(string preorder) {
/*基本思想:根据先序二叉树和中序/后序的不同 先序遍历先访问根节点 中序和后续先访问叶节点*/
int degree = 1;//根节点出度-入度 为2 比正常节点出度-入度 多1
for(int i=0;i<preorder.size();i++){
if(degree==0)
return false;
if(preorder[i]==',')
continue;
if(preorder[i]=='#')//遇到叶节点度数减一
degree-=1;
else{
while(i<preorder.size()&&preorder[i]!=',')//处理节点编号为多位数字的情况
i++;
degree+=1;
}
}
return degree==0;
}
};