面试题37_序列化二叉树

题目描述

请实现两个函数,分别用来序列化和反序列化二叉树

二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。

二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。

题解一

这题的细节特别麻烦,折腾了好久才AC成功。本题对于二叉树的序列化和反序列化的规则是自定义的,即给定一个二叉树,可以以自定义的规则进行序列化,但是要保证反序列化出的二叉树和输入的二叉树一模一样。我的规则是在每个节点后输出一个逗号,例如:

    1
   / \
  2   3
     / \
    4   5

输入的二叉树如上所示,经序列化后,得到字符串:"1,2,#,#,3,4,#,#,5,#,#,"

这里使用先序遍历的深度优先查找,序列化二叉树即在先序遍历二叉树时将节点输出。重点是在碰到空节点时也要输出#,因为序列中的#能够决定二叉树的结构,没有这个空节点#,单靠先序序列是无法恢复出原来的二叉树的,即反序列化。

在反序列化时,也是使用先序遍历的模板,用到了StringBuilder这个数据结构,而不直接用String。因为String在java中是不可变对象,是被final修饰的,每次对String修改,都会创建一个新的String,浪费时间和空间。除了StringBuilder,也可以考虑使用字符数组的方式,这就需要考虑索引的问题了。

下面是参考代码:

public String serialize(TreeNode root) {
    StringBuilder builder = new StringBuilder();
    serializeHelper(root, builder);
    return builder.toString();
}

private void serializeHelper(TreeNode node, StringBuilder builder) {
    if (node == null) {
        builder.append("#,");
        return;
    }
    builder.append(node.val).append(',');
    serializeHelper(node.left, builder);
    serializeHelper(node.right, builder);
}

public TreeNode deserialize(String str) {
    return deserializeHelper(new StringBuilder(str));
}

private TreeNode deserializeHelper(StringBuilder builder) {
    // 递归终止条件与空节点的处理
    if (builder.length() == 0)
        return null;
    if (builder.charAt(0) == '#') {
        builder.delete(0,2);
        return null;
    }

    // 取出当前根节点的值存进num
    int index = builder.indexOf(",");
    int num = Integer.parseInt(builder.substring(0,index));
    builder.delete(0,index+1);

    // 先序遍历
    TreeNode root = new TreeNode(num);
    root.left = deserializeHelper(builder);
    root.right = deserializeHelper(builder);
    return root;
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容