文章目录
题目:
序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。
请设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。
示例:
你可以将以下二叉树:
1
/ \
2 3
/ \
4 5
序列化为 "[1,2,3,null,null,4,5]"
提示: 这与 LeetCode 目前使用的方式一致,详情请参阅 LeetCode 序列化二叉树的格式。你并非必须采取这种方式,你也可以采用其他的方法解决这个问题。
说明: 不要使用类的成员 / 全局 / 静态变量来存储状态,你的序列化和反序列化算法应该是无状态的。
解法1:递归
/**
* 思路:
* 二叉树的序列化本质上是对其值进行编码
* 所以不是说必须返回 "[1,2,3,null,null,4,5]"。
* 比如这个方法实际返回:1,2,null,null,3,4,null,null,5,null,null
*
* 序列化:遍历树,将遍历的结果放入String中,null就加入"null "
* 反序列化:将String切割,放入队列中。不断的出队,如果null就返回null。如果不是就创建节点,之后创建其左右节点,最后返回当前节点
*/
static class TreeNode{
int val;
TreeNode left;
TreeNode right;
public TreeNode(int data){
this.val=data;
}
}
public static void main(String[] args) {
TreeNode t1 = new TreeNode(1);
TreeNode t2 = new TreeNode(2);
TreeNode t3 = new TreeNode(3);
TreeNode t4 = new TreeNode(4);
TreeNode t5 = new TreeNode(5);
t1.left=t2;
t1.right=t3;
t3.left=t4;
t3.right=t5;
new Recursive_master().deserialize(new Recursive_master().serialize(t1));
System.out.println();
}
// Encodes a tree to a single string.
public String serialize(TreeNode root) {
return recursive(root, "");
}
private String recursive(TreeNode root, String s) {
if (root==null)return s+="null ";
s+=root.val+" ";
s=recursive(root.left,s);
s=recursive(root.right,s);
return s;
}
// Decodes your encoded data to tree.
public TreeNode deserialize(String data) {
String[] vals = data.split(" ");
LinkedList<String> queue = new LinkedList<>(Arrays.asList(vals));
return build_tree(queue);
}
private TreeNode build_tree(LinkedList<String> queue) {
String poll = queue.poll();
if (poll.equals("null"))return null;
TreeNode node = new TreeNode(Integer.valueOf(poll));
node.left=build_tree(queue);
node.right=build_tree(queue);
return node;
}
序列化复杂度:
时间复杂度:On
空间复杂度:O1
反序列化复杂度:
时间复杂度:On
空间复杂度:On
解法2:队列
/**
* 思路:
* 序列化:当前节点的左右节点不断的入队
* 反序列化:
* 从根节点开始,遍历String
* 根据我们序列化的特点,当前节点的左节点:2*n+1,右节点:2*n+2
* 当前的i就是左节点的位置,++i就是右节点的位置
* 不断的入队左右节点
*/
// Encodes a tree to a single string.
public String serialize(TreeNode root) {
if (root == null) return "";
StringBuilder res = new StringBuilder();
LinkedList<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()){
TreeNode poll = queue.poll();
if (poll==null){
res.append("null ");
continue;
}
res.append(poll.val+" ");
queue.add(poll.left);
queue.add(poll.right);
}
return res.toString();
}
// Decodes your encoded data to tree.
public TreeNode deserialize(String data) {
if (data.equals(""))return null;
String[] vals = data.split(" ");
ArrayDeque<TreeNode> queue = new ArrayDeque<>();
TreeNode root = new TreeNode(Integer.valueOf(vals[0]));
queue.offer(root);
for (int i=1;i<vals.length;i++){
TreeNode poll = queue.poll();
if (!vals[i].equals("null")){
TreeNode left = new TreeNode(Integer.valueOf(vals[i]));
queue.offer(left);
poll.left=left;
}
if (!vals[++i].equals("null")){
TreeNode right = new TreeNode(Integer.valueOf(vals[i]));
queue.offer(right);
poll.right=right;
}
}
return root;
}
序列化复杂度:
时间复杂度:On
空间复杂度:On
反序列化复杂度:
时间复杂度:On
空间复杂度:On
解法3:递归(超出内存限制)
/**
* 思路:
* 序列化:遍历树,把树的形态存入到数组中
* 反序列化:从根节点开始递归的构建树
*
* 用到的技巧:
* 1.基本类型的数组不能存放null,object[]
* 2.数组长度不够,动态扩容
* 3.扩容的时候怎么让传入的数组扩容,把数组设置成全局的,扩容后赋值。就可以解决参数是引用的问题
*/
static Object[] arr = new Object[16];
// Encodes a tree to a single string.
public String serialize(TreeNode root) {
if (root==null)return "[]";
StringBuilder res = new StringBuilder();
recursive(root,0);
res.append("[");
int index=0;
for (int i=arr.length-1;i>=0;i--){
if (arr[i]!=null){
index=i;
break;
}
}
for (int i=0;i<=index;i++){
if (arr[i]!=null){
if (i==index)
res.append(arr[i]);
else
res.append(arr[i]+",");
}
else res.append("null"+",");
}
res.append("]");
return String.valueOf(res);
}
private void recursive(TreeNode root, int index) {
while (index>=arr.length)grow();
if (root==null){
arr[index]=null;
return;
}
arr[index]=root.val;
recursive(root.left,index*2+1);
recursive(root.right,index*2+2);
}
private void grow() {
int oldCapacity = arr.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
// minCapacity is usually close to size, so this is a win:
arr=Arrays.copyOf(arr, newCapacity);
}
// Decodes your encoded data to tree.
public TreeNode deserialize(String data) {
if (data=="[]")return null;
TreeNode root = new TreeNode((Integer) arr[0]);
buildTree(root,0);
return root;
}
private void buildTree(TreeNode root, int i) {
if (root==null)return;
if (arr[i * 2 + 1]==null)
root.left = null;
else
root.left = new TreeNode((Integer) arr[i * 2 + 1]);
if (arr[i * 2 + 2]==null)
root.right = null;
else
root.right = new TreeNode((Integer) arr[i * 2 + 2]);
buildTree(root.left,i*2+1);
buildTree(root.right,i*2+2);
}
序列化复杂度:
时间复杂度:On^2
空间复杂度:On
反序列化复杂度:
时间复杂度:On
空间复杂度:On
内存超过限制,不过方法整体没错。如果严格的按照"[1,2,3,null,null,4,5]"这种形式返回,这个方法可行。
不过本题,二叉树的序列化本质上是对其值进行编码。没有必要严格的按照示例的格式。只要能完成序列化反序列化就是成功的。