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]的关系:
dfs recursive node即subs[i], node左子树是subs[i+1, ..] 直到遇到NULL, backtracking 紧接着是右子树.
iterative: 当subs[i]不为null, 一直往左下插, 当遇到null意味着要backtracking换边
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?