题目描述

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

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

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

序列化二叉树思路

使用广度优先(BFS)遍历所有节点(包括空节点),整体流程如下:

  1. 初始化字符串 res
  2. 初始化队列 queue,将 root 放入队列
  3. 检查队列是否为空:
    • 队列不为空:取出队首节点,如果节点为 null,那么 res 更新为 res + '#,';如果节点不是 null,那么 res 更新为 res + val,并且将节点的左右节点依次加入 queue。继续循环。
    • 队列为空:结束循环
  4. 返回"[" + res + "]"
    1
/ \
2 3
/ \
4 5

以上面这棵二叉树为例,它的序列化结果是"[1,2,3,#,#,4,5,#,#,#,#]"

序列化的代码实现如下:

// ac地址:https://leetcode-cn.com/problems/xu-lie-hua-er-cha-shu-lcof/
// 原文地址:https://xxoo521.com/2020-02-13-serialize-and-deserialize-btree/ /**
* Encodes a tree to a single string.
*
* @param {TreeNode} root
* @return {string}
*/
var serialize = function(root) {
if (!root) {
return "[]";
} let res = "";
let node = root;
const queue = [node];
while (queue.length) {
const front = queue.shift();
if (front) {
res += `${front.val},`;
queue.push(front.left);
queue.push(front.right);
} else {
res += "#,";
}
} res = res.substring(0, res.length - 1); // 去掉最后一个逗号 return `[${res}]`;
};

反序列化二叉树思路

以前面的二叉树为例,反序列话就是将字符串"[1,2,3,#,#,4,5,#,#,#,#]"重新还原成原来的二叉树。

反序列化流程如下:

  • 去掉字符串 res 前后的[],并将其按照,逗号切分得到数组 nodes
  • 初始化队列 queue,放入 nodes 的第一个值对应的节点,nodes 弹出第一个值
  • 检查队列是否为空:
    • 队列不为空。从 queue 取出队首元素。从 nodes 中取出第一个值和第二值,依次处理。继续循环。
    • 队列为空。结束循环。
  • 返回根节点。

反序列化函数的设计关键是:数组 nodes 取出元素的顺序和原二叉树层序遍历的顺序是对应的。

反序列的函数实现如下:

// ac地址:https://leetcode-cn.com/problems/xu-lie-hua-er-cha-shu-lcof/
// 原文地址:https://xxoo521.com/2020-02-13-serialize-and-deserialize-btree/ /**
* Decodes your encoded data to tree.
*
* @param {string} data
* @return {TreeNode}
*/
var deserialize = function(data) {
if (data.length <= 2) {
return null;
} const nodes = data.substring(1, data.length - 1).split(",");
const root = new TreeNode(parseInt(nodes[0]));
nodes.shift(); const queue = [root];
while (queue.length) {
const node = queue.shift();
// 第一个是左节点,节点为空,直接跳过
const leftVal = nodes.shift();
if (leftVal !== "#") {
node.left = new TreeNode(leftVal);
queue.push(node.left);
}
// 第二个是右节点,节点为空,直接跳过
const rightVal = nodes.shift();
if (rightVal !== "#") {
node.right = new TreeNode(rightVal);
queue.push(node.right);
}
} return root;
};

更多资料

  • LeetCode 297.序列化二叉树 - JavaScript的更多相关文章

    1. LeetCode 101.对称二叉树 - JavaScript

      题目描述:给定一个二叉树,检查它是否是镜像对称的. 题目分析 下面这种二叉树就是镜像对称的,符合题目要求: 1 / \ 2 2 / \ / \ 3 4 4 3 解法 1:递归检查 根据题目" ...

    2. Java实现 LeetCode 297 二叉树的序列化与反序列化

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

    3. Leetcode 297.二叉树的序列化和反序列化

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

    4. Leetcode 331.验证二叉树的前序序列化

      验证二叉树的前序序列化 序列化二叉树的一种方法是使用前序遍历.当我们遇到一个非空节点时,我们可以记录下这个节点的值.如果它是一个空节点,我们可以使用一个标记值记录,例如#. 例如,上面的二叉树可以被序 ...

    5. Java实现 LeetCode 331 验证二叉树的前序序列化

      331. 验证二叉树的前序序列化 序列化二叉树的一种方法是使用前序遍历.当我们遇到一个非空节点时,我们可以记录下这个节点的值.如果它是一个空节点,我们可以使用一个标记值记录,例如 #. _9_ / \ ...

    6. Same Tree 序列化二叉树

      https://oj.leetcode.com/problems/same-tree/ Given two binary trees, write a function to check if the ...

    7. 每日一题 - 剑指 Offer 37. 序列化二叉树

      题目信息 时间: 2019-06-29 题目链接:Leetcode tag:序列化 二叉树 队列 难易程度:中等 题目描述: 请实现两个函数,分别用来序列化和反序列化二叉树. 示例: 1 / \ 2 ...

    8. 【剑指Offer】序列化二叉树 解题报告(Python)

      [剑指Offer]序列化二叉树 解题报告(Python) 标签(空格分隔): 剑指Offer 题目地址:https://www.nowcoder.com/ta/coding-interviews 题目 ...

    9. 剑指Offer 61. 序列化二叉树 (二叉树)

      题目描述 请实现两个函数,分别用来序列化和反序列化二叉树 题目地址 https://www.nowcoder.com/practice/cf7e25aa97c04cc1a68c8f040e71fb84 ...

    随机推荐

    1. Java后台技术(TDDL)

      从PC客户端开发转项目经理已经有一段时间了,感觉还不错,平安这边的项目经理还需要对外,所以部门其他项目经理经常需要出差去见客户,我专门对内,部门所有的开发和测试每天做什么.接下来做什么我都必须了解,部 ...

    2. Vacuum Pump Manufacturer - Vacuum Pump: Prevents Reactive Compound Decomposition Products

      Vacuum packaging has been popular in the industry for a long time. Many large companies have joined ...

    3. JavaScript动画相关

      JS动画原理 通过CSS缓慢变化从而实现动画效果 获取css属性 Window.getComputedStyle()方法返回一个对象,该对象在应用活动样式表并解析这些值可能包含的任何基本计算后报告元素 ...

    4. Jmeter_Http默认请求值

      1.线程组->配置原件->Http请求默认值 2.作用:几个Http 请求参数都是重复的数据 3.优先级:Http请求默认值和单个Http请求数值,使用单个Http请求数值为主 举例如下: ...

    5. 一、FreeMarker实现对js和css压缩

      1.代码压缩理解:实际上就是将原有的文本中无用的注释.空行.空格去掉来压缩文件的大小.进行js和css压缩会带来如下好处:1)减小了文件的体积,减少文件占用的内存;2)减小了网络传输量和带宽占用; 3 ...

    6. Python基础入门语法1

      PY的交换值的方法 x.y = y.x PY既具有动态脚本的特性,又有面向对象的特性 PY的缺点: 编译型的语言(C++,C):通过编译器进行编译成机器码,越接近底层,开发效率低 解释型代码:PY和J ...

    7. linux修改文件的权限和修改文件所有者和所属组

      文件设定法:chmod    [who]   [+][-][=]   [mode] who 文件所有者:u 文件所属组:g 其他:o 所有人:a +  添加权限 -  减少权限 =  覆盖原来权限 权 ...

    8. C/C++网络编程3——地址族与数据序列

      C/C++网络编程2中介绍了套接字,这一节介绍给套接字分配ip和端口号.ip用于标识一台主机,端口号用于标识一个主机中的一个应用程序,端口号占16位,0到65535,其中0到1023是知名端口号. 表 ...

    9. C++代码如何附加到C#写的主程序中?

      背景是这样:C#的exe程序,C#中调用C++的dll,也就是所谓的托管吧. C#的exe出了点问题,想在C++的dll的源码中调试,附加到进程时,加了断点,怎么也跟不进去.断点不变红啊,急死了. 最 ...

    10. 学习之学习--混沌大学商学院--第一课--HHR计划

      <学习之学习> 第一课:混沌初开 李善友 1,课程目标:建立个人的多元思维模型,帮助企业找到创新驱动的增长战略. 2,创新:第二曲线创新,创新理论之父熊彼特. 3,核心课:第二曲线,非连续 ...