LeetCode——449. 序列化和反序列化二叉搜索树

简介: LeetCode——449. 序列化和反序列化二叉搜索树

449. 序列化和反序列化二叉搜索树


题目描述

答案

我的答案

官方答案

后序遍历


题目描述


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


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


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


示例 1:

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

输出:[2,1,3]


示例 2:

输入:root = []

输出:[]


提示:

树中节点数范围是 [0, 104]

0 <= Node.val <= 104

题目数据 保证 输入的树是一棵二叉搜索树。


答案


我的答案


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


官方答案


前言


二叉搜索树是一种特殊的二叉树,序列化和反序列化过程也可以参照「297. 二叉树的序列化与反序列化」的过程。二叉搜索树的特殊之处在于其中序遍历是有序的,可以利用这一点来优化时间和空间复杂度。


后序遍历


思路


给定一棵二叉树的「先序遍历」和「中序遍历」可以恢复这颗二叉树。给定一棵二叉树的「后序遍历」和「中序遍历」也可以恢复这颗二叉树。而对于二叉搜索树,给定「先序遍历」或者「后序遍历」,对其经过排序即可得到「中序遍历」。因此,仅对二叉搜索树做「先序遍历」或者「后序遍历」,即可达到序列化和反序列化的要求。此题解采用「后序遍历」的方法。


序列化时,只需要对二叉搜索树进行后序遍历,再将数组编码成字符串即可。


反序列化时,需要先将字符串解码成后序遍历的数组。在将后序遍历的数组恢复成二叉搜索树时,不需要先排序得到中序遍历的数组再根据中序和后序遍历的数组来恢复二叉树,而可以根据有序性直接由后序遍历的数组恢复二叉搜索树。后序遍历得到的数组中,根结点的值位于数组末尾,左子树的节点均小于根节点的值,右子树的节点均大于根节点的值,可以根据这些性质设计递归函数恢复二叉搜索树。


代码

public class Codec {
    public String serialize(TreeNode root) {
        List<Integer> list = new ArrayList<Integer>();
        postOrder(root, list);
        String str = list.toString();
        return str.substring(1, str.length() - 1);
    }
    public TreeNode deserialize(String data) {
        if (data.isEmpty()) {
            return null;
        }
        String[] arr = data.split(", ");
        Deque<Integer> stack = new ArrayDeque<Integer>();
        int length = arr.length;
        for (int i = 0; i < length; i++) {
            stack.push(Integer.parseInt(arr[i]));
        }
        return construct(Integer.MIN_VALUE, Integer.MAX_VALUE, stack);
    }
    private void postOrder(TreeNode root, List<Integer> list) {
        if (root == null) {
            return;
        }
        postOrder(root.left, list);
        postOrder(root.right, list);
        list.add(root.val);
    }
    private TreeNode construct(int lower, int upper, Deque<Integer> stack) {
        if (stack.isEmpty() || stack.peek() < lower || stack.peek() > upper) {
            return null;
        }
        int val = stack.pop();
        TreeNode root = new TreeNode(val);
        root.right = construct(val, upper, stack);
        root.left = construct(lower, val, stack);
        return root;
    }
}


复杂度分析


时间复杂度:O(n),其中 n 是树的节点数。serialize 需要 O(n) 时间遍历每个点。deserialize 需要 O(n) 时间恢复每个点。


空间复杂度:O(n),其中 n 是树的节点数。serialize 需要 O(n) 空间用数组保存每个点的值,递归的深度最深也为 O(n)。deserialize 需要 O(n) 空间用数组保存每个点的值,递归的深度最深也为 O(n)。

相关文章
|
2月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
4天前
|
存储 XML JSON
用示例说明序列化和反序列化
用示例说明序列化和反序列化
|
12天前
|
JSON fastjson Java
niubility!即使JavaBean没有默认无参构造器,fastjson也可以反序列化。- - - - 阿里Fastjson反序列化源码分析
本文详细分析了 Fastjson 反序列化对象的源码(版本 fastjson-1.2.60),揭示了即使 JavaBean 沲有默认无参构造器,Fastjson 仍能正常反序列化的技术内幕。文章通过案例展示了 Fastjson 在不同构造器情况下的行为,并深入探讨了 `ParserConfig#getDeserializer` 方法的核心逻辑。此外,还介绍了 ASM 字节码技术的应用及其在反序列化过程中的角色。
41 10
|
13天前
|
存储 Java 开发者
Java编程中的对象序列化与反序列化
【9月更文挑战第20天】在本文中,我们将探索Java编程中的一个核心概念——对象序列化与反序列化。通过简单易懂的语言和直观的代码示例,你将学会如何将对象状态保存为字节流,以及如何从字节流恢复对象状态。这不仅有助于理解Java中的I/O机制,还能提升你的数据持久化能力。准备好让你的Java技能更上一层楼了吗?让我们开始吧!
|
21天前
|
存储 Java
Java编程中的对象序列化与反序列化
【9月更文挑战第12天】在Java的世界里,对象序列化与反序列化是数据持久化和网络传输的关键技术。本文将带你了解如何通过实现Serializable接口来标记一个类的对象可以被序列化,并探索ObjectOutputStream和ObjectInputStream类的使用,以实现对象的写入和读取。我们还将讨论序列化过程中可能遇到的问题及其解决方案,确保你能够高效、安全地处理对象序列化。
|
3天前
|
JSON 安全 编译器
扩展类实例的序列化和反序列化
扩展类实例的序列化和反序列化
11 0
|
9天前
|
XML Dubbo Java
分布式-序列化,反序列化
分布式-序列化,反序列化
|
2月前
|
存储 Java
Java编程中的对象序列化与反序列化
【8月更文挑战第28天】在Java世界中,对象序列化与反序列化是数据持久化和网络传输的关键技术。本文将深入浅出地探讨这一过程,带你领略其背后的原理及应用,让你的程序在数据的海洋中自由航行。
|
2月前
|
算法
LeetCode第96题不同的二叉搜索树
文章介绍了LeetCode第96题"不同的二叉搜索树"的解法,利用动态规划的思想和递推公式,通过计算以任意节点为根的不同二叉搜索树的数量,解决了该问题。
LeetCode第96题不同的二叉搜索树
|
1月前
|
存储 Java
Java编程中的对象序列化与反序列化
【9月更文挑战第2天】在Java的世界里,对象序列化和反序列化就像是给数据穿上了一件隐形的斗篷。它们让数据能够轻松地穿梭于不同的系统之间,无论是跨越网络还是存储在磁盘上。本文将揭开这层神秘的面纱,带你领略序列化和反序列化的魔法,并展示如何通过代码示例来施展这一魔法。
17 0
下一篇
无影云桌面