持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第30天,点击查看活动详情
题目(Serialize and Deserialize Binary Tree)
链接:https://leetcode-cn.com/problems/serialize-and-deserialize-binary-tree
解决数:1228
通过率:58.5%
标签:树 深度优先搜索 广度优先搜索 设计 字符串 二叉树
相关公司:facebook amazon microsoft
序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。
请设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。
提示: 输入输出格式与 LeetCode 目前使用的方式一致,详情请参阅 LeetCode 序列化二叉树的格式。你并非必须采取这种方式,你也可以采用其他的方法解决这个问题。
示例 1:
输入: root = [1,2,3,null,null,4,5]
输出: [1,2,3,null,null,4,5]
示例 2:
输入: root = []
输出: []
示例 3:
输入: root = [1]
输出: [1]
示例 4:
输入: root = [1,2]
输出: [1,2]
提示:
- 树中结点数在范围
[0, 104]
内 -1000 <= Node.val <= 1000
思路 DFS(递归)
- 递归遍历一棵树,重点关注当前节点,它的子树的遍历交给递归完成: “serialize函数,请帮我分别序列化我的左右子树,我等你返回的结果,再拼接一下。”
- 选择前序遍历,是因为 的打印顺序,在反序列化时更容易定位出根节点的值。
- 遇到 null 节点也要翻译成特定符号,反序列化时才知道这里是 null。
序列化的代码
const serialize = (root) => {
if (root == null) { // 遍历到 null 节点
return 'X';
}
const left = serialize(root.left); // 左子树的序列化结果
const right = serialize(root.right); // 右子树的序列化结果
return root.val + ',' + left + ','+ right; // 按 根,左,右 拼接字符串
};
func (this *Codec) serialize(root *TreeNode) string {
if root == nil {
return "X"
}
return strconv.Itoa(root.Val) + "," + this.serialize(root.Left) + "," + this.serialize(root.Right)
}
反序列化——也是递归
- 前序遍历的序列化字符串,就像下图右一:
- 定义函数 buildTree 用于还原二叉树,传入由序列化字符串转成的 list 数组。
- 逐个 pop 出 list 的首项,构建当前子树的根节点,顺着 list,构建顺序是根节点,左子树,右子树。
- 如果弹出的字符为 "X",则返回 null 节点。
- 如果弹出的字符是数值,则创建root节点,并递归构建root的左右子树,最后返回root。
反序列化的代码
const deserialize = (data) => {
const list = data.split(','); // split成数组
const buildTree = (list) => { // 基于list构建当前子树
const rootVal = list.shift(); // 弹出首项,获取它的“数据”
if (rootVal == "X") { // 是X,返回null节点
return null;
}
const root = new TreeNode(rootVal); // 不是X,则创建节点
root.left = buildTree(list); // 递归构建左子树
root.right = buildTree(list); // 递归构建右子树
return root; // 返回当前构建好的root
};
return buildTree(list); // 构建的入口
};