描述

序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。

请设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。

示例

示例1:
serdeser.jpg

  1. 输入:root = [1,2,3,null,null,4,5]
  2. 输出:[1,2,3,null,null,4,5]

示例2:

输入:root = []
输出:[]

示例3:

输入:root = [1]
输出:[1]

示例4:

输入:root = [1,2]
输出:[1,2]

提示

  • 输入输出格式与 LeetCode 目前使用的方式一致,详情请参阅 LeetCode 序列化二叉树的格式。你并非必须采取这种方式,也可以采用其他的方法解决这个问题。
  • 树中结点数在范围 [0, 104]
  • -1000 <= Node.val <= 1000

解题思路

思路一:BFS

  • 序列化

    • 用BFS遍历树,与一般遍历的不同点是不管node的左右子节点是否存在,统统加到队列中
    • 在节点出队时,如果节点不存在,在返回值res中加入一个”null“;如果节点存在,则加入节点值的字符串形式
  • 反序列化

    • 同样使用BFS方法,利用队列新建二叉树
    • 首先要将data转换成列表,然后遍历,只要不为null将节点按顺序加入二叉树中;同时还要将节点入队
    • 队列为空时遍历完毕,返回根节点

      代码

      public class Codec {
      
      // Encodes a tree to a single string.
      public String serialize(TreeNode root) {
         if(root == null){
             return "";
         }
         StringBuilder res = new StringBuilder();
         res.append("[");
         Queue<TreeNode> queue = new LinkedList<>();
         queue.offer(root);
         while(!queue.isEmpty()){
             TreeNode node = queue.poll();
             if(node != null){
                 res.append("" + node.val);
                 queue.offer(node.left);
                 queue.offer(node.right);
             }else{
                 res.append("null");
             }
             res.append(",");
         }
         res.append("]");
         return res.toString();
      }
      
      // Decodes your encoded data to tree.
      public TreeNode deserialize(String data) {
         if(data == ""){
             return null;
         }
         String[] dataList = data.substring(1, data.length() - 1).split(",");
         TreeNode root = new TreeNode(Integer.parseInt(dataList[0]));
         Queue<TreeNode> queue = new LinkedList<>();
         queue.offer(root);
         int i = 1;
         while(!queue.isEmpty()){
             TreeNode node = queue.poll();
             if(!"null".equals(dataList[i])){
                 node.left = new TreeNode(Integer.parseInt(dataList[i]));
                 queue.offer(node.left);
             }
             i++;
             if(!"null".equals(dataList[i])){
                 node.right = new TreeNode(Integer.parseInt(dataList[i]));
                 queue.offer(node.right);
             }
             i++;
         }
         return root;
      }
      }
      

      复杂度分析

  • 时间复杂度:O(n)

  • 空间复杂度:O(n)

思路二:DFS

  • 序列化


  1. 递归的第一步都是特例的处理,因为这是递归的中止条件:如果根节点为空,返回”null“
  2. 序列化的结果为:根节点值 + “,” + 左子节点值(进入递归) + “,” + 右子节点值(进入递归)
  3. 递归就是不断将“根节点”值加到结果中的过程
  • 反序列化


  1. 先将字符串转换成队列(python转换成列表即可)
  2. 接下来就进入了递归
    1. 弹出左侧元素,即队列出队
    2. 如果元素为“null”,返回null(python返回None)
    3. 否则,新建一个值为弹出元素的新节点
    4. 其左子节点为队列的下一个元素,进入递归;右子节点为队列的下下个元素,也进入递归
    5. 递归就是不断将子树的根节点连接到父节点的过程

代码

public class Codec {

    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        if(root == null){
            return "null";
        }
        return root.val + "," + serialize(root.left) + "," + serialize(root.right);  
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        Queue<String> queue = new LinkedList<>(Arrays.asList(data.split(",")));
        return dfs(queue);
    }

    private TreeNode dfs(Queue<String> queue) {
        String val = queue.poll();
        if("null".equals(val)){
            return null;
        }
        TreeNode root = new TreeNode(Integer.parseInt(val));
        root.left = dfs(queue);
        root.right = dfs(queue);
        return root;
    }
}

复杂度分析

  • 时间复杂度:O(n)
  • 空间复杂度:O(n)