Serialize and Deserialize Binary Tree

https://leetcode.com/problems/serialize-and-deserialize-binary-tree/description/

Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network connection link to be reconstructed later in the same or another computer environment.

Design an algorithm to serialize and deserialize a binary tree. There is no restriction on how your serialization/deserialization algorithm should work. You just need to ensure that a binary tree can be serialized to a string and this string can be deserialized to the original tree structure.

Thoughts

这道题开始想用传统的数组存储法做,即中间结点是root, 左边的是左子树,右边的是右子树。但它的缺点很明显,一来代码写的长,二来所需空间多(即使只存所在位置也无济于事),三来算中点时可能越界。

后来看到高手写的用preorder serialize 和同样调用preorder deserialize, 值得学习。

dfs顺着最左一路捅到底(遇到NULL), backtracking(回栈顶)换边, 继续捅

node/cur是当前, subs[i]是要被插入的, 遇到NULL停止继续搜索.

deserilize当前点和subs[i]的关系:

  1. dfs recursive node即subs[i], node左子树是subs[i+1, ..] 直到遇到NULL, backtracking 紧接着是右子树.

  2. iterative: 当subs[i]不为null, 一直往左下插, 当遇到null意味着要backtracking换边

  3. bfs i和i+1一定是node的左和右.

Code

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Codec {
    private final String SPLITER = "/";
    private final String NULL = "#";

    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        StringBuilder sb = new StringBuilder();
        if (root == null) {
            sb.append(NULL).append(SPLITER);
        } else {
            sb.append(root.val).append(SPLITER);
            sb.append(serialize(root.left));
            sb.append(serialize(root.right));
        }
        return sb.toString();
    }

    int i = -1;
    private TreeNode dfs(String[] subs) {
        i++;
        if (subs[i].equals(NULL)) {
            return null;
        }
        TreeNode node = new TreeNode(Integer.parseInt(subs[i]));
        node.left = dfs(subs);
        node.right = dfs(subs);
        return node;
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        String[] subs = data.split(SPLITER);
        return dfs(subs);
    }
}

// Your Codec object will be instantiated and called as such:
// Codec codec = new Codec();
// codec.deserialize(codec.serialize(root));

Analysis

时间复杂度O(n), 空间复杂度O(n).

Ver.2

栈内存当前的path, iterative解法的难点在于知道什么时候该backtracing和backtracing到哪里. 由于是二叉树, 有个比较巧妙的解法, 类似在树上做traversal, 维持cur和stack (当前path). 在树上做时是当cur为null时, 让栈顶及父节点帮助改变遍历方向. 这里是用cur来帮助转方向, 让stack只要遇到NULL就pop, 当连遇到两个NULL时意味是叶子, stack中把叶子和它的父节点都pop出来, cur指向父节点. 还有当进入右子节点时, 上一个访问的一定是NULL.

Ver.3

当是k叉树(k已知)时, 就不能遇到NULL就pop了. 栈依然是path, 栈顶是当前节点. 我们可以用一个map做计数器, 记录每个节点已经访问过了几个边. 当所有边都已经访问过时, pop/backtracing. 由于可能出现连续pop/backtracking的情况, 用一个循环连续检查栈顶.

Ver. 4

BFS

Last updated

Was this helpful?