zoukankan      html  css  js  c++  java
  • LeetCode OJ 297. Serialize and Deserialize Binary Tree

    Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network connection link to be reconstructed later in the same or another computer environment.

    Design an algorithm to serialize and deserialize a binary tree. There is no restriction on how your serialization/deserialization algorithm should work. You just need to ensure that a binary tree can be serialized to a string and this string can be deserialized to the original tree structure.

    For example, you may serialize the following tree

        1
       / 
      2   3
         / 
        4   5
    

    as "[1,2,3,null,null,4,5]", just the same as how LeetCode OJ serializes a binary tree. You do not necessarily need to follow this format, so please be creative and come up with different approaches yourself.

     Note: Do not use class member/global/static variables to store states. Your serialize and deserialize algorithms should be stateless.

    Credits:
    Special thanks to @Louis1992 for adding this problem and creating all test cases.

    【解析1】

    其实LeetCode上树的表示方式就挺好,即"[1,2,3,null,null,4,5]"这种形式,我们接下来就实现以下这种序列化。

    序列化比较容易,我们做一个层次遍历就好,空的地方用null表示,稍微不同的地方是题目中示例得到的结果是"[1,2,3,null,null,4,5,null,null,null,null,]",即 4 和 5 的两个空节点我们也存了下来。

    饭序列化时,我们根据都好分割得到每个节点。需要注意的是,反序列化时如何寻找父节点与子节点的对应关系,我们知道在数组中,如果满二叉树(或完全二叉树)的父节点下标是 i,那么其左右孩子的下标分别为 2*i+1 和 2*i+2,但是这里并不一定是满二叉树(或完全二叉树),所以这个对应关系需要稍作修改。如下面这个例子:

           5
          / 
         4   7
        /   /
       3   2
      /   /
     -1  9

    序列化结果为[5,4,7,3,null,2,null,-1,null,9,null,null,null,null,null,]。

    其中,节点 2 的下标是 5,可它的左孩子 9 的下标为 9,并不是 2*i+1=11,原因在于 前面有个 null 节点,这个 null 节点没有左右孩子,所以后面的节点下标都提前了2。所以我们只需要记录每个节点前有多少个 null 节点,就可以找出该节点的孩子在哪里了,其左右孩子分别为 2*(i-num)+1 和 2*(i-num)+2(num为当前节点之前 null 节点的个数)。

    【java代码】非递归

     1 /**
     2  * Definition for a binary tree node.
     3  * public class TreeNode {
     4  *     int val;
     5  *     TreeNode left;
     6  *     TreeNode right;
     7  *     TreeNode(int x) { val = x; }
     8  * }
     9  */
    10 public class Codec {
    11 
    12     // Encodes a tree to a single string.
    13     public String serialize(TreeNode root) {
    14         StringBuilder sb = new StringBuilder();  
    15         Queue<TreeNode> queue = new LinkedList<TreeNode>();  
    16         queue.offer(root);  
    17           
    18         while (!queue.isEmpty()) {  
    19             TreeNode node = queue.poll();  
    20             if (node == null) {  
    21                 sb.append("null,");  
    22             } else {  
    23                 sb.append(String.valueOf(node.val) + ",");  
    24                 queue.offer(node.left);  
    25                 queue.offer(node.right);  
    26             }  
    27         }  
    28           
    29         return sb.toString();
    30     }
    31 
    32     // Decodes your encoded data to tree.
    33     public TreeNode deserialize(String data) {
    34         if (data == null || data.isEmpty()) return null;  
    35           
    36         String[] vals = data.split(",");  
    37         int[] nums = new int[vals.length]; // 节点i之前null节点的个数  
    38         TreeNode[] nodes = new TreeNode[vals.length];  
    39           
    40         for (int i = 0; i < vals.length; i++) {   //计算每个节点前面null节点的数目
    41             if (i > 0) {  
    42                 nums[i] = nums[i - 1];  
    43             }  
    44             if (vals[i].equals("null")) {  
    45                 nodes[i] = null;  
    46                 nums[i]++;  
    47             } else {  
    48                 nodes[i] = new TreeNode(Integer.parseInt(vals[i]));  
    49             }  
    50         }  
    51           
    52         for (int i = 0; i < vals.length; i++) {  //对节点进行连接操作
    53             if (nodes[i] == null) {  
    54                 continue;  
    55             }  
    56             nodes[i].left = nodes[2 * (i - nums[i]) + 1];  
    57             nodes[i].right = nodes[2 * (i - nums[i]) + 2];  
    58         }  
    59           
    60         return nodes[0];
    61     }
    62 
    63 }

    【解析2】

    我们也可以用递归来解决这个问题:The idea is simple: print the tree in pre-order traversal and use "X" to denote null node and split node with ",". We can use a StringBuilder for building the string on the fly. For deserializing, we use a Queue to store the pre-order traversal and since we have "X" as null node, we know exactly how to where to end building subtress.

    这个思路用到的是树的前序遍历,因为序列中包含了值为null的节点,因此我们可以很容易地进行反序列化操作。

    【java代码】递归

     1 public class Codec {
     2     private static final String spliter = ",";
     3     private static final String NN = "X";
     4 
     5     // Encodes a tree to a single string.
     6     public String serialize(TreeNode root) {
     7         StringBuilder sb = new StringBuilder();
     8         buildString(root, sb);
     9         return sb.toString();
    10     }
    11 
    12     private void buildString(TreeNode node, StringBuilder sb) {
    13         if (node == null) {
    14             sb.append(NN).append(spliter);
    15         } else {
    16             sb.append(node.val).append(spliter);
    17             buildString(node.left, sb);
    18             buildString(node.right,sb);
    19         }
    20     }
    21     // Decodes your encoded data to tree.
    22     public TreeNode deserialize(String data) {
    23         Deque<String> nodes = new LinkedList<>();
    24         nodes.addAll(Arrays.asList(data.split(spliter)));
    25         return buildTree(nodes);
    26     }
    27 
    28     private TreeNode buildTree(Deque<String> nodes) {
    29         String val = nodes.remove();
    30         if (val.equals(NN)) return null;
    31         else {
    32             TreeNode node = new TreeNode(Integer.valueOf(val));
    33             node.left = buildTree(nodes);
    34             node.right = buildTree(nodes);
    35             return node;
    36         }
    37     }
    38 }
     
  • 相关阅读:
    面试题32
    面试题28. 对称的二叉树
    面试题55
    面试题04. 二维数组中的查找
    面试题58
    面试题57. 和为s的两个数字
    如果Python对于磁盘没有写入权限,还会运行吗?
    Python中的import语句
    Python决定一个变量时局部的,还是全局的,是在编译期
    Python中的Comprehensions和Generations
  • 原文地址:https://www.cnblogs.com/liujinhong/p/5484776.html
Copyright © 2011-2022 走看看