「这是我参与12月更文挑战的第17天,活动详情查看:2021最后一次更文挑战」
331. 验证二叉树的前序序列化
序列化二叉树的一种方法是使用前序遍历。当我们遇到一个非空节点时,我们可以记录下这个节点的值。如果它是一个空节点,我们可以使用一个标记值记录,例如 #。
_9_
/ \
3 2
/ \ / \
4 1 # 6
/ \ / \ / \
# # # # # #
例如,上面的二叉树可以被序列化为字符串 "9,3,4,#,#,1,#,#,2,#,6,#,#",其中 # 代表一个空节点。
给定一串以逗号分隔的序列,验证它是否是正确的二叉树的前序序列化。编写一个在不重构树的条件下的可行算法。
每个以逗号分隔的字符或为一个整数或为一个表示 null 指针的 '#' 。
你可以认为输入格式总是有效的,例如它永远不会包含两个连续的逗号,比如 "1,,3" 。
示例 1:
输入: "9,3,4,#,#,1,#,#,2,#,6,#,#"
输出: true
示例 2:
输入: "1,#"
输出: false
示例 3:
输入: "9,#,#,1"
输出: false
栈的思想
思路
我们知道树状数据结构会有左节点和有节点,我们用stack来保存树中的每个节点需要被填补的空节点数量
- 处理根节点,根节点为空时,此时只需要填补根节点一个空位,因此stack中默认有一个1,1代表此时拥有一个空节点
这里我们通过split,将字符串转成数组,得到所有节点的数组nodeArr,然后遍历处理没一个节点
-
如果节点为#,则代表有一个空节点被#代替,且不产生新的空节点,所以直接将stack中末尾的空节点数量-1,此时要判断,如果stack最后一个值为0,则代表该节点的空白都被填满,所以需要弹出
-
如果节点为数字,则代表有一个空节点被数字代替,且产生两个新节点,所以要先判断代替一个空节点后,stack末尾的空节点数量-1后是否为0,为0则弹出,不为0则不用处理,然后向stack中push一个2,2代表该数字节点产生的两个新的空节点
判断条件
- 如果是一个完整的树,最后应该没有空节点,所以只需要判断stack的length是否为0即可
var isValidSerialization = function (preorder) {
var nodeArr = preorder.split(',')
var stack = [1]
for (var i = 0; i < nodeArr.length; i++) {
if(stack.length===0) return false
var item = nodeArr[i]
stack[stack.length-1]--
if(stack[stack.length-1]===0){
stack.pop()
}
if (item !== '#') {
stack.push(2)
}
}
return stack.length===0
};
计数
思路
这里思想同上,只不过需要填补的节点我们用slot来记录
- 根节点未放置的时候,slot为1,表示需要放入一个节点来填补
- 每填补一个数字,则会占用一个节点,slot--,但是会新增两个空节点,slot+=2
- 每遇到一个#,则填补一个null到一个空节点,slot--
判断条件
- 最后只需要判断是否所有的节点都被填补,即slot===0
var isValidSerialization = function (preorder) {
var nodeArr = preorder.split(',')
var slot = 1
for (var i = 0; i < nodeArr.length; i++) {
if(slot===0) return false
var item = nodeArr[i]
switch(item){
case '#':
slot--
break;
default:
slot++
break;
}
}
return slot===0
};