「这是我参与2022首次更文挑战的第26天,活动详情查看:2022首次更文挑战」
题目
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
解法一
栈。
思路
假设树的每一个节点为一个槽位,那么一个数字节点必然会带来两个槽位,并且消耗掉一个槽位,而“#”节点,只会消耗掉1个槽位,最终如果槽位消耗完了,那么说明这个树结构是ok的。
不是树的情况总结有两种:
- 树的节点遍历完之后,槽位不为空,那么说明我们的树缺少节点来填充槽位。
- 比那里的途中如果我们需要槽位来装数字或者“#”的时候,槽位已经空了,那么树结构也是有问题的。
那么我们可以很快的想到,用栈数据结构来维护这个树的槽位。
具体的逻辑如下
- 处理原始数据为一个数组,用','来split。申明一个栈stack来存储槽位。
- 遍历数组,每遇到一个数字,我们就消耗一个槽位,增加两个槽位,那么等于就是弹出栈顶的元素,再压入两个元素,至于元素是什么,无所谓,只是用来占个位就好了。
- 每遇到一个“#”,我们就消耗一个槽位,即弹出栈顶的元素。
- 在这个过程中,每次进入循环我们都要判断当前stack是否为空,如果为空,则直接return false。
代码如下
/**
* @param {string} preorder
* @return {boolean}
*/
var isValidSerialization = function(preorder) {
// 如果树是空的,直接返回true。
if(preorder.length == 0){
return true;
}
let arr = preorder.split(',');
let stack = [];
// 由于我们树为空的状态已经判断过了,那么这里等于是往栈放入根节点的槽位。
stack.push(0);
for(let i=0;i<arr.length;i++){
if(stack.length == 0){
return false;
}
if(/\d/.test(arr[i])){
stack.pop();
stack.push(0);
stack.push(0);
} else if(arr[i] == '#'){
stack.pop();
}
}
return stack.length == 0;
};
复杂度分析
时间复杂度:O(n), 遍历一遍数组即可。
空间复杂度:O(n), 需要维护一个栈来存数据,如果树是一个链表,那栈的长度就为n/2,所以空间复杂度为O(n)。
解法二
计数器。
思路
上一个解法其实我们发现,我们用栈的思想来做,每次入栈的内容具体是什么我们不关心,那这里是否有优化的空间呢?当然有,并且可以给空间复杂度优化到O(1)。
就是因为每次入栈的内容我们不关心,那么我们可以用一个计数器来代替栈,每遇到一个数字,我们就把计数器 加1(因为先减1再加2,等于是加1),每遇到一个“#”,则计数器减1,结果判断逻辑和解法一一样。
代码如下
/**
* @param {string} preorder
* @return {boolean}
*/
var isValidSerialization = function(preorder) {
if(preorder.length == 0){
return true;
}
let arr = preorder.split(',');
let count = 1;
for(let i=0;i<arr.length;i++){
if(count == 0){
return false;
}
if(/\d/.test(arr[i])){
count++;
} else if(arr[i] == '#'){
count--;
}
}
return count == 0;
};
复杂度分析
时间复杂度:O(n)。
空间复杂度:O(1),只需要一个计数器来存储基计数即可。