PS:《剑指offer》是很多同学找工作都会参考的一本面试指南,同时也是一本算法指南(为什么它这么受欢迎,主要应该是其提供了一个循序渐进的优化解法,这点我觉得十分友好)。现在很多互联网的算法面试题基本上可以在这里找到影子,为了以后方便参考与回顾,现将书中例题用Java实现(第二版),欢迎各位同学一起交流进步。
GitHub: https://github.com/Uplpw/SwordOffer。
剑指offer完整题目链接: https://blog.csdn.net/qq_41866626/article/details/120415258
1 题目描述
实现两个函数,分别用来序列化和反序列化二叉树。
你需要设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。
leetcode链接: 序列化二叉树(以下代码已测试,提交通过)
2 测试用例
一般是考虑功能用例,特殊(边缘)用例或者是反例,无效测试用例这三种情况。甚至可以从测试用例寻找一些规律解决问题,同时也可以让我们的程序更加完整鲁棒。
(1)功能用例:完全与非完全二叉树。
(2)边缘用例:只有一个节点,只有左节点,只有右节点。
(3)无效用例:树为空。
3 思路
分析:
序列化在Java中,是指把Java对象转换为字节序列的过程;而Java反序列化是指把字节序列恢复为Java对象的过程。在本题中可简化一些,把树中节点值存储下来即可。
看到该题,会让人想到重建二叉树(根据前序中序或者中序后序恢复二叉树)。流程:(1)序列化:前序遍历序列和中序遍历序列,(2)反序列化:根据前序中序序列恢复二叉树。
但在本题有两个关键缺点:1. 全部数据都读取完才能进行反序列化。2. 该方法需要保证树中节点的值各不相同(本题无法保证)。
我们可以从另外一个角度出发:
(1)在遍历结果中,记录null指针后,那么任何一种遍历方式都能回推出原二叉树。
(2)期望边读取序列化数据,边反序列化二叉树,仅可以使用前序(本题使用前序)或层序遍历。
4 代码
树的结构:
public class TreeNode {
public int val;
public TreeNode left;
public TreeNode right;
public TreeNode(int val) {
this.val = val;
this.left = null;
this.right = null;
}
}
算法实现:
import java.util.LinkedList;
import java.util.Queue;
public class SerializeBinaryTrees {
// 递归实现前序遍历,并实现序列化
public static String serialize(TreeNode root) {
if (root == null)
return "null,";
StringBuilder result = new StringBuilder();
result.append(root.val);
result.append(",");
result.append(serialize(root.left));
result.append(serialize(root.right));
return result.toString();
}
// 反序列化
public static TreeNode deserialize(String data) {
StringBuilder stringBuilder = new StringBuilder(data);
return deserializeCore(stringBuilder);
}
public static TreeNode deserializeCore(StringBuilder stringBuilder) {
if (stringBuilder.length() == 0)
return null;
// 取出根节点的值
String num = stringBuilder.substring(0, stringBuilder.indexOf(","));
// 为了之后方便递归,删除当前节点
stringBuilder.delete(0, stringBuilder.indexOf(","));
// 删除多余 ','
stringBuilder.deleteCharAt(0);
// 根节点为空,直接返回null
if (num.equals("null"))
return null;
// 根据取出的根节点值,创建节点
TreeNode node = new TreeNode(Integer.parseInt(num));
// 递归创建左子树、右子树
node.left = deserializeCore(stringBuilder);
node.right = deserializeCore(stringBuilder);
return node;
}
public static void main(String[] args) {
// 1
// / \
// 2 3
// / / \
// 4 5 6
// 1,2,4,$,$,$,3,5,$,$,6,$,$
TreeNode root = new TreeNode(1);
root.left = new TreeNode(2);
root.right = new TreeNode(3);
root.left.left = new TreeNode(4);
root.right.left = new TreeNode(5);
root.right.right = new TreeNode(6);
String result = serialize(root);
System.out.println("序列化结果:" + result);
}
}
参考
在解决本书例题时,参考了一些大佬的题解,比如leetcode上的官方、K神,以及其他的博客,在之后的每个例题详解后都会给出参考的思路或者代码链接,同学们都可以点进去看看!
本例题参考:
本文如有什么不足或不对的地方,欢迎大家批评指正,最后希望能和大家一起交流进步、拿到心仪的 offer !!!