序列化二叉树的一种方法是使用 前序遍历。给定一串以逗号分隔的序列,验证它是否是正确的二叉树的前序序列化。编写一个在不重构树的条件下的可行算法。
栈在解决字符串的配对问题上有奇效。比如移除无效的括号,栈匹配等等。。。如果把节点及左右节点当成一组,也可以用类似的匹配思路去解决。
以 9,3,4,#,#,1,#,#,2,#,6,#,#
为例
- 首先考虑字符
9
,他肯定有左右两个节点,所以先将表示他数量的2
入栈
- 下一个字符
,
,只是连接符,跳过 - 下一个字符
3
,表明节点9
的左节点是节点3
,将栈顶(节点9对应的子节点数量
)减 1
,同时节点3
也有两个节点,将节点3
子节点数量2
入栈,栈变成
- 下一个字符
4
,表明节点3
的左节点是节点4
,将栈顶(节点3对应的子节点数量
)减 1
,同时节点4
也有两个节点,将节点4
子节点数量2
入栈,栈变成
- 下一个字符
#
,表明节点4
的左节点为null
,将栈顶(节点4对应的子节点数量
)减 1
:
- 下一个字符
#
,表明节点4
的右节点为null
- 此时栈顶数量为
0
,将0
弹出,
- 下一个字符
1
,表明节点3
的右节点是1
,将栈顶(节点3对应的子节点数量
)减 1
,此时栈顶数量为0
,将0
弹出,同时将字符1
的左右节点数量2
入栈
-
下两个
#
,将节点1
的左右节点数量减2
-
接下来的所有逻辑,在
1-9
中都能找到相似的逻辑处理。。。。。。 -
如果在扫描过程中,栈已空,表明序列化是无效的;如果字符扫描完成,栈为空,表明是有效的前序序列化
具体代码:
function isValidSerialization(preorder: string): boolean {
// 头节点
const stack = [1]
let len = preorder.length
let i = 0
while (i < len) {
if (stack.length === 0) {
return false
}
// 跳过
if (preorder[i] === ',') {
i++
} else if (preorder[i] === '#') {
// 栈顶数量 -1, 如果为0, 出栈
if (--stack[stack.length - 1] === 0) {
stack.pop()
}
i++
} else {
// 这里是对 多位数 的处理
while (i < len && preorder[i] !== ',') {
i++
}
if (--stack[stack.length - 1] === 0) {
stack.pop()
}
// 节点有两个子节点
stack.push(2)
i++
}
}
return stack.length === 0
}