leetcode——从先序序列判断是否为二叉树(中等)


哈哈哈,孩子高兴疯了,半个小时的时间编出代码,用时打败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,然后维护一个计数器。其实这种想法更正统一般一些,有值得学习的地方。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值