1 题目描述
请实现两个函数,分别用来序列化和反序列化二叉树。
你可以将以下二叉树:
1
/ \
2 3
/ \
4 5
序列化为 "[1,2,3,null,null,4,5]"
2 解题思路
通常使用的前序、中序、后序、层序遍历记录的二叉树的信息不完整,即唯一的输出序列可能对应着多种二叉树可能性。题目要求的序列化和反序列化是可逆操作。因此,序列化的字符串应携带完整的二叉树信息。
观察题目示例,序列化的字符串实际上是二叉树的 “层序遍历”(BFS)结果,本文也采用层序遍历。
为完整表示二叉树,考虑将叶节点下的null
也记录。在此基础上,对于列表中任意某节点node
,其左子节点node.left
和右子节点node.right
在序列中的位置都是唯一确定的。如下图所示:
上图规律可总结为下表:
node.val | node的索引 | node.left的索引 | node.right的索引 |
---|---|---|---|
1 | 0 | 1 | 2 |
2 | 1 | 3 | 4 |
3 | 2 | 5 | 6 |
4 | 5 | 7 | 8 |
5 | 6 | 9 | 10 |
设m为列表区间[0,n]中的null节点个数,则可总结出根节点、左子节点、右子节点的列表索引的递推公式:
node.val | node的列表索引 | node.left的列表索引 | node.right的列表索引 |
---|---|---|---|
≠ \neq = null | n | 2(n-m)+1 | 2(n-m)+2 |
= null | n | 无 | 无 |
序列化使用层次遍历实现。反序列化通过以上递推公式反推各节点在序列中的索引,进而实现。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Codec {
// Encodes a tree to a single string.
public String serialize(TreeNode root) {
if (root == null) return "[]";
StringBuilder res = new StringBuilder("[");
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
while (!q.isEmpty()) {
TreeNode node = q.poll();
if (node != null) {
res.append(node.val + ",");
q.offer(node.left);
q.offer(node.right);
}
else {
res.append("null,");
}
}
res.append("]");
res.deleteCharAt(res.length()-1);
return res.toString();
}
// Decodes your encoded data to tree.
public TreeNode deserialize(String data1) {
if (data1 == "[]") return null;
String[] data = data1.substring(1,data1.length() - 1).split(",");
Queue<TreeNode> q = new LinkedList();
TreeNode root = new TreeNode(Integer.parseInt(data[0]));
q.offer(root);
int i = 1;
while (!q.isEmpty()) {
TreeNode node = q.poll();
if (!data[i].equals("null")) {
node.left = new TreeNode(Integer.parseInt(data[i]));
q.offer(node.left);
}
i++;
if (!data[i].equals("null")) {
node.right = new TreeNode(Integer.parseInt(data[i]));
q.offer(node.right);
}
i++;
}
return root;
}
}
// Your Codec object will be instantiated and called as such:
// Codec codec = new Codec();
// codec.deserialize(codec.serialize(root));
序列化复杂度分析:
- 时间复杂度O(N):N为二叉树的节点数,层序遍历需要访问所有节点,最差情况下需要访问N+1个null,总体复杂度为O(2N+1)=O(N)。
- 空间复杂度O(N):最差情况下,队列queue同时存储(N+1)/2个节点(或N+1个null),使用O(N);列表使用O(N)。
反序列化复杂度分析:
- 时间复杂度O(N):N为二叉树的节点数,按层构建二叉树需要遍历整个vals,其长度最大为2N+1。
- 空间复杂度O(N):最差情况下,队列queue同时存储(N+1)/2个节点,因此使用O(N)额外空间。