LeetCode算法学习之--Recursion--二叉树的序列化与反序列化

297 阅读4分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

大家好今天给大家分享下一道 LeetCode 困难难度 的题目297. 二叉树的序列化与反序列化

题目

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

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

提示: 输入输出格式与 LeetCode 目前使用的方式一致,详情请参阅 LeetCode 序列化二叉树的格式。你并非必须采取这种方式,你也可以采用其他的方法解决这个问题。

示例 1:(图片来自leetcode)

image.png

输入: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]

分析

1.树转字符串

2.字符串转回tree

解法

1.递归

2.迭代

解法一:递归

思路

序列化
1.先采用用前序遍历的方式访问每个节点,并记录到res数组中
2.如果遇到了空节点null 则使用 “X”来占位
3.最后把数组转化成字符串

反序列化
1.先把字符串转化成数组queue
2.再使用递归的方式一个一个的queue中的元素,然后使用TreeNode(val) 转化成节点
3.最后返回树节点
*/

var serialize = function (root) {
  // 特殊条件,如果root为空
  if (!root) return "X";

  //   res记录所有节点的值
  const res = [];

  //   前序数列遍历每个节点
  function recur(root) {
    //   遇到为空的节点 “X"来占位
    if (!root) {
      res.push("X");
      return;
    }

    res.push(root.val);
    recur(root.left);
    recur(root.right);
  }

  recur(root);
  //   把数组转化成字符串
  return res.join(",");
};

var deserialize = function (data) {
  if (data === "X") return null;

  function recur(queue) {
    //   终止条件
    if (queue[0] === "X") {
      queue.shift();
      return null;
    }
    // 构建节点
    const node = new TreeNode(queue.shift());
    // 递归给左右节点赋值
    node.left = recur(queue);
    node.right = recur(queue);

    // 返回节点
    return node;
  }

  //   转化成数组
  const queue = data.split(",");
  return recur(queue);
};

/* 复杂度
时间 O(n)
空间 O(n)
*/

解法二:迭代

思路
序列化
1.采用层序遍历遍历tree, res为字符串,添加root.val 以逗号隔离
2.采用"x"来占位
3.返回res字符串

反序列化
1.采用split 来把字符串转为数组
2.在以queue的方式来模拟递归
3.每个迭代中 重新组装节点


*/

var serialize = function (root) {
  // 特殊情况的处理
  if (!root) return "X";

  // 字符串来记录节点的值
  let res = "";

  // queue 来模拟递归的栈
  const queue = [];
  queue.push(root);

  //  从上往下访问节点
  while (queue.length) {
    const node = queue.shift();
    if (node) {
      res += node.val + ",";
      queue.push(node.left);
      queue.push(node.right);
    } else {
      // "x“ 作为占位符
      res += "X,";
    }
  }

  return res;
};

var deserialize = function (data) {
  if (data === "X") {
    return null;
  }

  //   list 存储值
  const list = data.split(",");

  const root = new TreeNode(list.shift());
  //   queue 存储节点
  const queue = [];
  queue.push(root);
  while (queue.length) {
    //   构建treeNode
    const node = queue.shift();

    /* 如果节点为null 则执行下一次迭代 */
    if (!node) continue;
    // 取出左右节点的值
    const leftVal = list.shift();
    const rightVal = list.shift();

    // 构建左节点
    const leftNode = leftVal !== "X" ? new TreeNode(leftVal) : null;
    node.left = leftNode;
    queue.push(leftNode);

    // 构建右节点
    const rightNode = rightVal !== "X" ? new TreeNode(rightVal) : null;
    node.right = rightNode;
    queue.push(rightNode);
  }

  return root;
};

/* 复杂度
时间 O(n)
空间 O(n)
*/

总结

今天这道题是主要是练习递归和迭代的方式来拆分tree和rebuildtree

大家可以看看我分享的一个专栏(前端搞算法)里面有更多关于算法的题目的分享,希望能够帮到大家,我会尽量保持每天晚上更新,如果喜欢的麻烦帮我点个赞,十分感谢

大家如果对“TS”感兴趣的可以看看我的专栏 (TypeScript常用知识),感谢大家的支持

文章内容目的在于学习讨论与分享学习算法过程中的心得体会,文中部分素材来源网络,如有侵权,请联系删除,邮箱 182450609@qq.com