题目
序列化二叉树的一种方法是使用 前序遍历 。当我们遇到一个非空节点时,我们可以记录下这个节点的值。如果它是一个空节点,我们可以使用一个标记值记录,例如 #。
例如,上面的二叉树可以被序列化为字符串 "9,3,4,#,#,1,#,#,2,#,6,#,#",其中 # 代表一个空节点。
给定一串以逗号分隔的序列,验证它是否是正确的二叉树的前序序列化。编写一个在不重构树的条件下的可行算法。
保证 每个以逗号分隔的字符或为一个整数或为一个表示 null 指针的 '#' 。
你可以认为输入格式总是有效的
- 例如它永远不会包含两个连续的逗号,比如
"1,,3"。
注意: 不允许重建树。
示例 1:
输入: preorder = "9,3,4,#,#,1,#,#,2,#,6,#,#"
输出: true
示例 2:
输入: preorder = "1,#"
输出: false
示例 3:
输入: preorder = "9,#,#,1"
输出: false
提示:
1 <= preorder.length <= 104preorder由以逗号“,”分隔的[0,100]范围内的整数和“#”组成
题解
解题思路
方法一
大致思路是我们可以按前序顺序把给出的元素填充到树中,如果刚好可以填充完成,则表示是合法的,否则则非法。
虽然不能重建树,但是我们可以借助栈来判断,设定栈中的每个元素值(整数)表示对应树节点当前剩余的节点槽数(可填充节点数)。
处理过程大致为:
- 如果当前元素是数字,则需要把当前栈顶节点值减 1(如果减为 0,则出栈),并且给栈中 push 节点 2,这是因为当前元素填充后会占掉一个槽,但是该元素同时会再提供两个槽(左右子树);
- 如果当前元素是 #,因为是空节点,所以只需把当前栈顶节点值减 1(如果减为 0,则出栈),无需增加槽。
在此过程中,如果字符串中元素还没处理完,出现栈为空的情况,说明不是正确的二叉树的前序序列化,直接返回 false 即可。待所有元素处理完,此时如果栈为空,则说明合法。之所以这种方法成立,主要是因为我们每填充一个非空元素,都给剩余节点槽数加 1(+2-1),这符合二叉树的特性,所以如果是正确的二叉树的前序序列化,最终肯定能填充完成并且剩余节点槽数为 0。
方法二
方法一实现的空间复杂度为 O(n),可以考虑优化为常量级的空间复杂度。
方法一的实现中,不难发现,实际其中的栈可以看作是一个整体,实际无需使用栈存储各节点对应的剩余节点槽数,而是可以直接使用一个整数来存储总的剩余槽数即可。
这样一来,空间复杂度就优化为了 O(1),而且实现也比较简单,下面给出的代码正是基于这种方法。
代码
class Solution {
public boolean isValidSerialization(String preorder) {
String[] splits = preorder.split(",");
int slots = 1;
for (String s : splits) {
if (slots == 0) {
return false;
}
if (s.equals("#")) {
// 空结点
slots--;
} else {
// 数字节点 slots = slots - 1 + 2
slots++;
}
}
return slots == 0;
}
}
复杂度分析
-
时间复杂度:O(n)\
-
空间复杂度:O(1)
优质项目推荐
推荐一个可用于练手、毕业设计参考、增加简历亮点的项目。
lemon-puls/txing-oj-backend: Txing 在线编程学习平台,集在线做题、编程竞赛、即时通讯、文章创作、视频教程、技术论坛为一体