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

题目

序列化是将数据结构或对象转换为一系列位的过程,以便它可以存储在文件或内存缓冲区中,或通过网络连接链路传输,以便稍后在同一个或另一个计算机环境中重建。
设计一个算法来序列化和反序列化 二叉搜索树 。 对序列化/反序列化算法的工作方式没有限制。 您只需确保二叉搜索树可以序列化为字符串,并且可以将该字符串反序列化为最初的二叉搜索树。
编码的字符串应尽可能紧凑

示例:

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

解答 & 代码

利用二叉搜索树的性质,可以避免序列化空指针,实现更紧凑的编码

解法一:先序 + 中序构建二叉树

本题是二叉搜索树,因此可以借助二叉搜索树的性质,实现更紧凑的编码
二叉搜索树的性质:二叉搜索树的中序遍历序列是递增序列
因此,

  • 编码:只需编码得到二叉搜索树的先序遍历序列即可(无需编码空指针)
  • 解码:将先序遍历序列按升序排序,就得到了二叉搜索树的中序遍历序列,根绝先序遍历序列和中序遍历序列重建二叉树 ```cpp /**

    • Definition for a binary tree node.
    • struct TreeNode {
    • int val;
    • TreeNode *left;
    • TreeNode *right;
    • TreeNode(int x) : val(x), left(NULL), right(NULL) {}
    • }; */ class Codec { private: unordered_map inOrderMap; // key = 节点值,val = 中序遍历序列中的下标

      // 递归由先序和中序遍历序列构建二叉树 TreeNode* dfsBuildTree(vector& preOrder, int preStart, int preEnd, int inStart, int inEnd) {

      1. if(preStart > preEnd)
      2. return NULL;
      3. int rootVal = preOrder[preStart];
      4. TreeNode* root = new TreeNode(rootVal);
      5. int InOrderRootIdx = inOrderMap[rootVal];
      6. int leftLen = InOrderRootIdx - inStart;
      7. root->left = dfsBuildTree(preOrder, preStart + 1, preStart + leftLen, inStart, InOrderRootIdx - 1);
      8. root->right = dfsBuildTree(preOrder, preStart + leftLen + 1, preEnd, InOrderRootIdx + 1, inEnd);
      9. return root;

      } public:

      // Encodes a tree to a single string. // 编码得到二叉树的先序遍历序列字符串,数值之间用空格隔开 string serialize(TreeNode* root) {

      1. if(root == NULL)
      2. return "";
      3. string result;
      4. result += to_string(root->val);
      5. if(root->left != NULL)
      6. result += " " + serialize(root->left);
      7. if(root->right != NULL)
      8. result += " " + serialize(root->right);
      9. return result;

      }

      // Decodes your encoded data to tree. TreeNode* deserialize(string data) {

      1. istringstream istr(data);
      2. vector<int> preOrder; // 先序遍历数组
      3. string val;
      4. while(istr >> val)
      5. preOrder.push_back(stoi(val));
      6. vector<int> inOrder = preOrder; // 中序遍历数组(先序遍历数组升序排序得到)
      7. sort(inOrder.begin(), inOrder.end());
      8. for(int i = 0; i < inOrder.size(); ++i)
      9. inOrderMap[inOrder[i]] = i;
      10. // 递归由先序和中序遍历序列构建二叉树
      11. return dfsBuildTree(preOrder, 0, preOrder.size() - 1, 0, inOrder.size() - 1);

      } };

// 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;

  1. 复杂度分析:设二叉树节点数为 N
  2. - 时间复杂度 O(N):
  3. - 空间复杂度 O(N):
  4. 执行结果:

执行结果:通过

执行用时:32 ms, 在所有 C++ 提交中击败了 62.15% 的用户 内存消耗:30.9 MB, 在所有 C++ 提交中击败了 20.38% 的用户

  1. <a name="UyKjT"></a>
  2. ## 解法二:先序序列构建二叉搜索树
  3. 可以利用**二叉搜索树的另一个性质:根节点的值大于所有左子树节点的值,小于所有右子树节点的值**<br />因此,
  4. - **编码**:只需编码得到二叉搜索树的**先序遍历**序列即可(无需编码空指针)
  5. - **解码**:递归用先序遍历序列,以及节点值范围构建二叉搜索树
  6. ```cpp
  7. /**
  8. * Definition for a binary tree node.
  9. * struct TreeNode {
  10. * int val;
  11. * TreeNode *left;
  12. * TreeNode *right;
  13. * TreeNode(int x) : val(x), left(NULL), right(NULL) {}
  14. * };
  15. */
  16. class Codec {
  17. private:
  18. // 利用先序遍历序列和节点取值范围,递归构建二叉搜索树
  19. TreeNode* dfsBuildBST(deque<int>& preOrderQ, int minVal, int maxVal)
  20. {
  21. // 递归结束条件 1:如果序列为空,则返回 NULL
  22. if(preOrderQ.size() == 0)
  23. return NULL;
  24. // 递归结束条件 2:如果根节点的值不在限定的上下界范围内,则返回 NULL
  25. int rootVal = preOrderQ.front();
  26. if(rootVal <= minVal || rootVal >= maxVal)
  27. return NULL;
  28. preOrderQ.pop_front(); // 弹出根节点
  29. TreeNode* root = new TreeNode(rootVal); // 构建根节点
  30. // 递归构建左、右子树(收缩节点的取值范围)
  31. root->left = dfsBuildBST(preOrderQ, minVal, rootVal);
  32. root->right = dfsBuildBST(preOrderQ, rootVal, maxVal);
  33. return root; // 返回根节点
  34. }
  35. public:
  36. // Encodes a tree to a single string.
  37. // 编码得到二叉树的先序遍历序列字符串,数值之间用空格隔开
  38. string serialize(TreeNode* root) {
  39. if(root == NULL)
  40. return "";
  41. string result;
  42. result += to_string(root->val);
  43. if(root->left != NULL)
  44. result += " " + serialize(root->left);
  45. if(root->right != NULL)
  46. result += " " + serialize(root->right);
  47. return result;
  48. }
  49. // Decodes your encoded data to tree.
  50. TreeNode* deserialize(string data) {
  51. // cout << data << endl;
  52. istringstream istr(data);
  53. deque<int> preOrderQ; // 双端队列,记录先序遍历序列
  54. string val;
  55. while(istr >> val)
  56. preOrderQ.push_back(stoi(val));
  57. return dfsBuildBST(preOrderQ, INT_MIN, INT_MAX);
  58. }
  59. };
  60. // Your Codec object will be instantiated and called as such:
  61. // Codec* ser = new Codec();
  62. // Codec* deser = new Codec();
  63. // string tree = ser->serialize(root);
  64. // TreeNode* ans = deser->deserialize(tree);
  65. // return ans;

复杂度分析:设二叉树节点数为 N

  • 时间复杂度 O(N):
  • 空间复杂度 O(N):

执行结果:

  1. 执行结果:通过
  2. 执行用时:36 ms, 在所有 C++ 提交中击败了 43.44% 的用户
  3. 内存消耗:29.9 MB, 在所有 C++ 提交中击败了 23.04% 的用户