一、需求
- 请实现两个函数,分别用来序列化和反序列化二叉树。
示例:
你可以将以下二叉树:
1
/ \
2 3
/ \
4 5
序列化为 "[1,2,3,null,null,4,5]"
二、层序遍历BFS
2.1 思路分析
- 题目要求的"序列化"和"反序列化"是可逆操作。因此,序列化的字符串应该携带"完整的"二叉树信息,即拥有单独表示二叉树的能力。
- 为使反序列化可行,考虑将越过叶节点的null也看作节点。如果是这样,对于列表中任意结点node,其左子结点node.left和右子结点node.right在序列中的位置是唯一确定的。
- 设m为列表区间[0,n]中空节点(即null)的个数,则可总结出node、node.left、node.right在列表索引中的对应关系:
2.2.1 序列化serialize
- 特例处理:若root为空,则直接返回空列表"[ ]";
- 初始化:队列queue(包含根节点root);序列化列表res;
- 层序遍历:当queue为空时跳出
1.节点出队,记为node;
2.若node不为空,打印字符串node.val,将左、右子节点加入到queue;
3.若node为空,则打印字符串"null";
4.返回值:拼接列表(用‘,’隔开,首尾添加中括号)。
2.2.2 序列化代码实现
public String serialize(TreeNode root) {
if(root == null) return "[]";
StringBuilder res = new StringBuilder("[");
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.add(root);
while(!queue.isEmpty()) {
TreeNode node = queue.poll();
if(node != null) {
res.append(node.val+",");
queue.add(node.left);
queue.add(node.right);
} else {
res.append("null,");
}
}
res.deleteCharAt(res.length()-1);
res.append("]");
return res.toString();
}
2.2.3 复杂度分析
- 时间复杂度为O(N),假设二叉树有N个节点,最坏情况下,二叉树退化为链表,需要遍历N个节点和N+1个null,因此时间复杂度为O(2N+1),即O(N);
- 空间复杂度为O(N),当二叉树为满二叉树时,队列最多存储(N+1)/2个元素,因此空间复杂度为O(N)。
2.3.1 反序列化deserialize
- 特例处理:若data为空,直接返回null;
- 初始化:序列化列表vals(先去掉首尾中括号,再用逗号隔开),指针i = i,根节点root( 值为vals[0] ),队列queue(包含root);
- 按层构建:当queue为空时跳出
1.节点出队,记为node;
2.构建node的左子节点:node.left的值为vals[i],并将node.left入队;
3.执行i += 1;
4.构建node的右子节点:node.right的值为vals[i],并将node.right入队;
5.执行i += 1;
4.返回值:返回根节点root即可。
2.3.2 反序列化代码实现
public TreeNode deserialize(String data) {
if(data.equals("[]")) return null;
String[] vals = data.substring(1,data.length()-1).split(",");
TreeNode root = new TreeNode(Integer.parseInt(vals[0]));
Queue<TreeNode> queue = new LinkedList<>() {{add(root);}};
int i = 1;
while(!queue.isEmpty()) {
TreeNode node = queue.poll();
if(!vals[i].equals("null")) {
node.left = new TreeNode(Integer.parseInt(vals[i]));
queue.add(node.left);
}
i++;
if(!vals[i].equals("null")) {
node.right = new TreeNode(Integer.parseInt(vals[i]));
queue.add(node.right);
}
i++;
}
return root;
}
2.3.3 复杂度分析
- 时间复杂度为O(N),N为二叉树的节点个数,按层构建二叉树需要遍历整个vals,其长度最大为2N+1;
- 空间复杂度为O(N),最差情况下,队列queue最多同时存储(N+1)/2个元素,因此使用O(N)的额外空间。
三、完整代码
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> queue = new LinkedList<TreeNode>();
queue.add(root);
while(!queue.isEmpty()) {
TreeNode node = queue.poll();
if(node != null) {
res.append(node.val+",");
queue.add(node.left);
queue.add(node.right);
} else {
res.append("null,");
}
}
res.deleteCharAt(res.length()-1);
res.append("]");
return res.toString();
}
// Decodes your encoded data to tree.
public TreeNode deserialize(String data) {
if(data.equals("[]")) return null;
String[] vals = data.substring(1,data.length()-1).split(",");
TreeNode root = new TreeNode(Integer.parseInt(vals[0]));
Queue<TreeNode> queue = new LinkedList<>() {{add(root);}};
int i = 1;
while(!queue.isEmpty()) {
TreeNode node = queue.poll();
if(!vals[i].equals("null")) {
node.left = new TreeNode(Integer.parseInt(vals[i]));
queue.add(node.left);
}
i++;
if(!vals[i].equals("null")) {
node.right = new TreeNode(Integer.parseInt(vals[i]));
queue.add(node.right);
}
i++;
}
return root;
}
}
四、参考地址
作者:jyd