哈哈哈,孩子高兴疯了,半个小时的时间编出代码,用时打败100%,内存打败87.91%,孩子从来打代码没有这么爽过。。。。。。
提示:这题感觉属于抖机灵那种,没什么编程技巧,代码量也不大
一、题目是什么?
序列化二叉树的一种方法是使用前序遍历。当我们遇到一个非空节点时,我们可以记录下这个节点的值。如果它是一个空节点,我们可以使用一个标记值记录。
_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
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/verify-preorder-serialization-of-a-binary-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
二、解答
1.我的解法
我的想法很简单,就是判断字符串里面#的个数是不是数字个数+1.
在之前的离散数学,数据结构里,我记得这样一条性质,二叉树里面,度为0的节点(也就是本题的空节点)是度为2的节点的数目+1,具体证明就是算两次,找边和顶点直接的关系,在此就不赘述了。
然后在反复提交修改的过程中,加了三个细节:
1、数字可以为多位的
2、空树的判断
3、null=node(d=2)+1,更完善一些,一旦先序序列的前 i 个元素满足了上面的关系,此时,如果后面还有元素,这也不是一颗二叉树。
代码如下:
class Solution {
public:
bool isValidSerialization(string preorder) {
int n=preorder.size();
int pre=0;
int tree=0,node=0;
if(preorder[0]=='#'&&n!=1) return false;//空树判断
for(int i=0;i<n;i++){
if(preorder[i]=='#') node++;
if(isdigit(preorder[i])&&pre!=i-1){//注意,这里的数字不一定是个位,要考虑到多位的情况
pre=i;
tree++;}
if(node==tree+1&&i!=n-1) return false; //如果前面已经成树,那么后面就不可能再和前面组成一棵新的二叉树了
}
if(node==tree+1) return true;
else return false;
}
};
2.官方解法
让我小小的骄傲一下,此时我想大声的说一句话:你个垃圾!!!(心酸,这都是以前我看完官方代码之后对自己说的话,风水轮流转啊。。。嚣张ing)官方思路:
方法一:栈
我们可以定义一个概念,叫做槽位。一个槽位可以被看作「当前二叉树中正在等待被节点填充」的那些位置。
二叉树的建立也伴随着槽位数量的变化。
如果遇到了空节点,则要消耗一个槽位;
如果遇到了非空节点,则除了消耗一个槽位外,还要再补充两个槽位。
此外,还需要将根节点作为特殊情况处理。
我们使用栈来维护槽位的变化。栈中的每个元素,代表了对应节点处剩余槽位的数量,而栈顶元素就对应着下一步可用的槽位数量。当遇到空节点时,仅将栈顶元素减 1;当遇到非空节点时,将栈顶元素减 1 后,再向栈中压入一个 2。无论何时,如果栈顶元素变为 0,就立刻将栈顶弹出。
遍历结束后,若栈为空,说明没有待填充的槽位,因此是一个合法序列;否则若栈不为空,则序列不合法。此外,在遍历的过程中,若槽位数量不足,则序列不合法。
复杂度分析
时间复杂度:O(n),其中 n为字符串的长度。我们每个字符只遍历一次,同时每个字符对应的操作都是常数时间的。
空间复杂度:O(n)。此为栈所需要使用的空间。
方法二:计数
能否将方法一的空间复杂度优化至 O(1) 呢?
回顾方法一的逻辑,如果把栈中元素看成一个整体,即所有剩余槽位的数量,也能维护槽位的变化。
因此,我们可以只维护一个计数器,代表栈中所有元素之和,其余的操作逻辑均可以保持不变。
PS:个人感觉代码一直在数空槽位的个数
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
方法二代码如下(示例):
class Solution {
public:
bool isValidSerialization(string preorder) {
int n = preorder.length();
int i = 0;
int slots = 1;
while (i < n) {
if (slots == 0) {
return false;//如果没有槽位了,但是还有元素,那么这个树就是错的啦
}
if (preorder[i] == ',') {
i++;
} else if (preorder[i] == '#'){
slots--;//遇到空节点,槽位被占用
i++;
} else {
// 读一个数字
while (i < n && preorder[i] != ',') {
i++;
}
slots++; // slots = slots - 1 + 2,遇到非空节点,槽位+1
}
}
return slots == 0;//判断条件哦
}
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/verify-preorder-serialization-of-a-binary-tree/solution/yan-zheng-er-cha-shu-de-qian-xu-xu-lie-h-jghn/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
总结
本题有两种思路,一种就是我的想法,发掘二叉树的数学性质,找到判断二叉树的充要条件。
一种就是官方的,找槽位,他没有深入挖掘二叉树的数学性质,但是想的很直接,只要没有槽位可以让节点填充,那么这个树就是false,然后维护一个计数器。其实这种想法更正统一般一些,有值得学习的地方。
本文探讨了如何验证一个字符串是否为正确的二叉树前序序列化形式,提供了两种解法:一是基于二叉树性质的简单判断方法,二是官方提出的槽位计数法,并附带代码实现。
632

被折叠的 条评论
为什么被折叠?



