LeetCode每日一题,331. Verify Preorder Serialization of a Binary Tree
先看题目描述
大意就是给定一个字符串表示的二叉树的前序遍历序列,其中数字代表非叶子节点,# 代表叶子节点,节点间通过逗号隔开,让我们通过前序遍历序列判断该二叉树是否是个完整的二叉树(即每个非叶子节点是否都有两个子节点)
算法和思路
栈
可以引入一个概念,叫做槽位,一个槽位可以看作是当前二叉树中正在等待被节点填充的位置
我们定义一个栈,初始时,栈中只有 1,栈顶元素对应着下一步可用的槽位数量,当遇到 # 即叶子节点时,则填充一个槽位,将栈顶元素减 1;当遇到数字即非叶子节点时,则将栈顶元素减 1,并将 2 添加至栈顶,代表填充一个槽位,同时引入两个新槽位。注意,当栈顶元素变为 0 时,就将该元素移除。最后检查栈是否为空即可,同时,在填充槽位的过程中,若槽位数量不足,同样是非法序列
算法源码
1 | class Solution { |
也可以把栈中元素看作一个整体,即用一个计数器维护所有的剩余槽位数量,初始时计数器的值为 1,当遇到 # 时将计数器减 1,代表消耗一个槽位;遇到数字时将计数器加 1,代表所有的剩余槽位数量增加了一个。过程中若出现槽位数量不够的情况就代表是个非法序列,最后判断计数器的值是否为 0 即可
1 | class Solution { |
下面是自己一开始实现的算法,也是使用的栈,但是引入了一个表示节点的数据结构,实现的没上面方法巧妙,运行速度较慢
1 | class Solution { |
其实上面的办法,总结下来,就是利用了完整二叉树的性质,即叶子节点的数目等于非叶子节点的数目 + 1
证明如下:设非叶子节点的数目为 m,叶子节点的数目为 n。由于非叶子节点的出度为 2,叶子节点的出度为 0,那么二叉树中边的数目为 2m,根据五环连通图的性质有 节点个数 = 边的个数 + 1,即节点个数为 2m + 1;又因为节点只包括非叶子节点和叶子节点,于是有节点个数 = m + n,故 m + n = 2m + 1,可得 n = m + 1