序列化是将数据结构或对象转换为一系列位的过程,以便它可以存储在文件或内存缓冲区中,或通过网络连接链路传输,以便稍后在同一个或另一个计算机环境中重建。

设计一个算法来序列化和反序列化 二叉搜索树 。 对序列化/反序列化算法的工作方式没有限制。 您只需确保二叉搜索树可以序列化为字符串,并且可以将该字符串反序列化为最初的二叉搜索树。

编码的字符串应尽可能紧凑。

 

示例 1:

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

示例 2:

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

 

提示:

  • 树中节点数范围是 [0, 104]
  • 0 <= Node.val <= 104
  • 题目数据 保证 输入的树是一棵二叉搜索树。

 

注意:不要使用类成员/全局/静态变量来存储状态。 你的序列化和反序列化算法应该是无状态的。

Related Topics
  • 深度优先搜索
  • 广度优先搜索
  • 设计
  • 二叉搜索树
  • 字符串
  • 二叉树
  • \n
  • 👍 201
  • 👎 0
  • 题解

    因为这是一棵搜索树,利用前序遍历的特性就可以,还原过程和之前的LeetCode刷题【1008】前序遍历构造二叉搜索树

    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode(int x) { val = x; }
     * }
     */
    public class Codec {
    
        List<Integer> list;
    
        // Encodes a tree to a single string.
        public String serialize(TreeNode root) {
            list = new ArrayList<>();
            dfs(root);
            return listToString();
        }
    
        //先序遍历记录内容
        public void dfs(TreeNode root){
            if (root == null) {
                return;
            }
            list.add(root.val);
            dfs(root.left);
            dfs(root.right);
        }
    
        public String listToString(){
            if (list.size()==0){
                return "";
            }
            StringBuilder str = new StringBuilder(""+list.get(0));
            for (int i = 1; i < list.size(); i++) {
                str.append(",").append(list.get(i));
            }
            return str.toString();
        }
    
        // Decodes your encoded data to tree.
        public TreeNode deserialize(String data) {
            if (data==null || data.length()==0){
                return null;
            }
            list = new ArrayList<>();
            String[] arr = data.split(",");
            for (String num : arr) {
                list.add(Integer.parseInt(num));
            }
            return deserializeByPreOrder(0,arr.length-1);
        }
    
        public TreeNode deserializeByPreOrder(int left, int right){
            if (left>right){
                return null;
            }
            TreeNode node = new TreeNode(list.get(left));
            if (left==right){
                return node;
            }
            //找到比node大的那个值为右子树的根节点
            int rightBegin = left;
            left++;
            while (rightBegin<=right && list.get(rightBegin) <= node.val){
                rightBegin++;
            }
            node.left = deserializeByPreOrder(left,rightBegin-1);
            node.right = deserializeByPreOrder(rightBegin,right);
            return node;
        }
    }
    
    // Your Codec object will be instantiated and called as such:
    // Codec ser = new Codec();
    // Codec deser = new Codec();
    // String tree = ser.serialize(root);
    // TreeNode ans = deser.deserialize(tree);
    // return ans;
    //leetcode submit region end(Prohibit modification and deletion)
    

    因为是二叉搜索树,有着明显的大小值有序的特性。

    如果换成是普通的二叉树,可以用BFS的方式序列化处理。null节点使用特殊非数字的字符替代即可或者直接留空可以,解析的时候同样按“,”逗号分割,如果得到的是空字符串则表示null。

    还有一个通用二叉树的思路,比如有二叉树如下

                 5
               /   \
              4     7
             /     / \
             2   6   8
              \
              3

    按照结构序列化如下,使用“[”“]”“,”来分割表示

    5[4[,2[,3]],],7[6,8]]

    借助栈的先进后出的特性,来实现,分析过程如下

    • 读取到5,构建一个val为5的node节点入栈,此时栈内元素【5】
    • 读取到4,继续构建入栈,此时栈内元素【4,5】
    • 读取到一个空节点,构建个空节点入栈,此时栈内元素【null,4,5】
    • 读取到2,构建一个2节点入栈,此时栈内元素【2,null,4,5】
    • 读取到一个空节点,构建一个空节点入栈,此时栈内元素【null,2,null,4,5】
    • 读取到3,构建个3节点入栈,此时栈内元素【3,null,2,null,4,5】
    • 接下来是关键,遇到了“]”字符,取出栈顶两个元素,依次分别为取出后栈顶元素的右节点和左节点,即3节点为2节点的右子节点,null节点为2节点的左子节点。此时栈内元素【2,null,4,5】,2下面挂靠了null和3节点
    • 接下来又遇到了“]”字符,同样取出栈顶两个元素,挂靠到对应节点下面,即2节点挂到4节点的右子节点位置,null节点挂在4节点的左子节点位置,此时栈内元素【4,5】
    • 之后继续遇到了7,创建节点并入栈。【7,4,5】
    • 又分别遇到了6和7,继续入栈。【8,6,7,4,5】
    • 再次遇到“]”,把弹出放在7节点下。此时栈内剩下【7,4,5】
    • 再次遇到“]”,把7、4节点弹出放在5节点下
    • 最终结束二叉树构建完成