AcWing
  • 首页
  • 课程
  • 题库
  • 更多
    • 竞赛
    • 题解
    • 分享
    • 问答
    • 应用
    • 校园
  • 关闭
    历史记录
    清除记录
    猜你想搜
    AcWing热点
  • App
  • 登录/注册

LeetCode 331. Verify Preorder Serialization of a Binary Tree    原题链接    中等

作者: 作者的头像   yxc ,  2018-06-27 23:12:07 ,  所有人可见 ,  阅读 2928


8


9

题目描述

一种把二叉树序列化的方式是使用前序遍历。当我们遇到非空节点时,直接记录它的值;当我们遇到空节点时,记录#。

     _9_
    /   \
   3     2
  / \   / \
 4   1  #  6
/ \ / \   / \
# # # #   # #

例如,上述二叉树可以被序列化成"9,3,4,#,#,1,#,#,2,#,6,#,#",#表示空节点。

给定一个用逗号隔开的序列,请判断它是不是一个合法的二叉树前序遍历。请不要将二叉树重建出来。

被逗号隔开的值要么是整数,要么是#。

给定的序列一定是合法的。例如,不会出现两个连续逗号的情况:1,,3。

样例1

输入:"9,3,4,#,#,1,#,#,2,#,6,#,#"
输出:true

样例2

输入:"1,#"
输出:false

样例3

输入:"9,#,#,1"
输出:false

算法

(二叉树遍历) $O(n)$

一般来说,只给出前序遍历,并不能唯一确定一棵二叉树。但这道题目中还给出了所有空节点的位置,所以可以唯一确定一棵二叉树。

我们用先根顺序递归遍历整棵树,遍历时用一个指针在给定数组中指向当前节点的值,如果遇到#,则说明遇到了空节点,直接return;如果遇到整数,说明遍历到了树中的一个节点,我们先将指针后移,表示先输出根节点,然后依次递归遍历左子树和右子树。
如果递归还没结束但数组已经遍历完,或者递归结束但数组还没遍历完,则说明给定的序列不是一个合法的前序遍历。

时间复杂度分析:递归遍历时只将数组扫描了一遍,所以时间复杂度是 $O(n)$。

C++ 代码

class Solution {
public:
    bool ans = true;
    bool isValidSerialization(string preorder) {
        preorder += ',';
        int u = 0;
        dfs(preorder, u);
        return ans && u == preorder.size();
    }

    void dfs(string &preorder, int &u)
    {
        if (u == preorder.size())
        {
            ans = false;
            return;
        }
        if (preorder[u] == '#')
        {
            u += 2;
            return;
        }
        while (preorder[u] != ',') u ++ ; u ++ ;
        dfs(preorder, u);
        dfs(preorder, u);
    }
};

12 评论


用户头像
白胡子的花猫   2021-03-12 10:51         踩      回复

其实也可以选择不给字符串中加逗号,只需要检查一下把所有的数字遍历完成就行

while (pos < sz && isdigit(s[pos])) ++pos;
        ++pos;

用户头像
coffeebeansyy   2019-08-16 00:58         踩      回复

为什么 isValidSerialization 里面 需要 preorder += ',' 提前加个逗号?

用户头像
yxc   2019-08-16 01:16         踩      回复

后续代码里找当前节点时以','为结尾标志,就是这句:while (preorder[u] != ',') u ++ ; 所以为了方便在整个字符串最后加上了一个','。


用户头像
一只菜鸡   2019-08-03 23:11         踩      回复

原谅我太菜了,我还是不太懂为什么dfs里面 if (u == preorder.size()) 就要把ans = false;而结果是ans && u == preorder.size() 那不是肯定返回false吗?

用户头像
yxc   2019-08-03 23:30         踩      回复

if (u == preorder.size())是在判断是否在不该结束的时候结束了,如果在不该结束的时候结束了,就返回false,而最后ans && u == preorder.size();是在判断是否在该结束的时候没结束。

用户头像
一只菜鸡   2019-08-03 23:38         踩      回复

谢谢y总这么快速的解答!

用户头像
镇长   2020-09-04 13:44    回复了 yxc 的评论         踩      回复

y总 u 和 preorder.size() 都相等了,为啥还是 不该结束的时候结束了 ??

用户头像
yxc   2020-10-12 13:55    回复了 镇长 的评论         踩      回复

如果调用递归函数,就说明不该结束。


用户头像
greg666   2019-04-09 00:34         踩      回复

先序遍历一定以#终止dfs。dfs结束时也就是数组遍历结束时。
两个铁球同时着地。
这种思路第一次见过。这又是怎么想到的?

用户头像
yxc   2019-04-09 00:53         踩      回复

比较直观的想法就是直接模拟一遍前序遍历hh


用户头像
greg666   2019-04-09 00:26         踩      回复

两个dfs()之间的if可以去掉。

用户头像
yxc   2019-04-09 00:52         踩      回复

嗯,dfs函数开头的判断完全包含这个if判断,可以去掉。
已去掉~


App 内打开
你确定删除吗?
1024
x

© 2018-2025 AcWing 版权所有  |  京ICP备2021015969号-2
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息