Serialize and Deserialize Binary Tree
- Medium
- keyword: Recursion, pre-order, BFS, DFS
- 类似: Binary Tree
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.
- 例子:
1
/ \
/ \
-1 2
/
3
- 如上图: 有2种serialize: pre-order和level-order
- 先说level-order, 因为Leetcode的Binary Tree都是用的level order表示.
- serialize是: [1,-1,2,#,#,3]
- 再看看pre-order, 则是[1,-1,#,#,2,3,#,#,#]
idea1: level-order
Serialize: BFS, 简单.
- 即通过BFS来做, 注意null的情况. 我一开始想着leaf node不用加null儿子, 但发现这样是不对的, 例如上图中的
-1
, 他就必须加上null儿子, 否则不知道2是谁的儿子了. 这样会导致结尾多了3的null儿子. 所以我最后还处理了一下stringbuilder. - 代码如下:
public String serializeTTT(TreeNode root) {
StringBuilder sb = new StringBuilder();
if (root == null) return "null";
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
while (!q.isEmpty()) {
int sz = q.size();
for (int i = 0; i < sz; ++i) {
TreeNode cur = q.poll();
if (cur == null) {
sb.append("null,");
continue;
} else {
sb.append(cur.val + ",");
}
//if (cur.left == null && cur.right == null && q.size()==1) { 这样做会出错: [1,-1,2,#,#,3]
// continue;
//}
q.offer(cur.left);
q.offer(cur.right);
}
}
sb.deleteCharAt(sb.length() - 1);
String[] sbArr = sb.toString().split(",");
int i;
for (i = sbArr.length-1; i >= 0; i--) {
if (!sbArr[i].equals("null")) {
break;
}
}
return sb.substring(0, sb.length() - (sbArr.length-1-i)*5); // remove the trailing null
}
Deserialize
- 还是用BFS来做. 使用一个global pointer: i指向当前strs(通过split ','得到的string array). 如果str不是null, 则按顺序接到poll出来的cur的左右. 并push会queue, 从而在下一层使用.
- 代码如下, 注意: 这里就不用考虑trailing null.
public TreeNode deserializeTTT(String data) {
String[] strs = data.split(",");
Queue<TreeNode> q = new LinkedList<>();
TreeNode root = strs[0].equals("null") ? null : new TreeNode(Integer.valueOf(strs[0]));
q.offer(root);
int i = 1;
while (!q.isEmpty()) {
int sz = q.size();
for (int j = 0; j < sz; ++j) {
TreeNode node = q.poll();
if (node == null) continue;
if (i < strs.length && !strs[i].equals("null")) {
node.left = new TreeNode(Integer.valueOf(strs[i++]));
} else {
i++;
}
if (i < strs.length && !strs[i].equals("null")) {
node.right = new TreeNode(Integer.valueOf(strs[i++]));
} else {
i++;
}
q.offer(node.left);
q.offer(node.right);
}
}
return root;
}
idea2
- 这也是大部分人的写法, 为什么不用in-order/post-order呢? 因为只有pre-order保存了头节点, 从而可以Deserialize会tree. 而后两者则不行.
Serialize
- 简单的recursion.
- 代码如下
private static final String spliter = ",";
private static final String NN = "null";
public String serialize(TreeNode root) {
StringBuilder sb = new StringBuilder();
buildString(root, sb);
return sb.toString();
}
private void buildString(TreeNode node, StringBuilder sb) {
if (node == null) {
sb.append(NN).append(spliter);
} else {
sb.append(node.val).append(spliter);
buildString(node.left, sb);
buildString(node.right,sb);
}
}
Deserialize
- 这个是这题的关键. Serialize都是简单的, 因为按顺序遍历即可.
- 也是pre-order的recursion, 同时使用Queue, 保存的pre-order的序列.
- 代码如下
// Decodes your encoded data to tree.
public TreeNode deserialize(String data) {
Queue<String> nodes = new LinkedList<>();
nodes.addAll(Arrays.asList(data.split(spliter)));
return buildTree(nodes);
}
private TreeNode buildTree(Queue<String> nodes) {
String val = nodes.poll();
if (val.equals(NN)) return null;
else {
TreeNode node = new TreeNode(Integer.valueOf(val));
node.left = buildTree(nodes);
node.right = buildTree(nodes);
return node;
}
}