[H二叉树] lc297. 二叉树的序列化与反序列化(二叉树+前序遍历+中序遍历+面试经典)

Posted Ypuyu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[H二叉树] lc297. 二叉树的序列化与反序列化(二叉树+前序遍历+中序遍历+面试经典)相关的知识,希望对你有一定的参考价值。

1. 题目来源

链接:297. 二叉树的序列化与反序列化

相同:[剑指-Offer] 37. 序列化二叉树(层序遍历、前序遍历、递归、特殊情况)

参考题解:BFS和DFS两种方式解决

2. 题目解析

之前写过这题,但是当时还没有学算法,写的很垃圾。

仅给前序遍历是无法建树的,必须有中序的加入才可以。可以证明,中序遍历+任一其它序遍历都可以唯一构建一颗二叉树。

本题采用序列化方式构建二叉树,将空节点也保存起来,这样就能重建树了。

  • 基于树的遍历,任一遍历方式并保存空节点位置,都可以反序列化建树。
  • 常见是层序、先序。
  • 在此,使用先序递归的方式建树。层序采用的是 bfs 形式的建树。

当然,作为一个二叉树,也可以通过保存前序、中序来重新构建二叉树。 在此就不讨论了。


时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)


先序序列化、反序列化: 基于 dfs递归。

class Codec {
public:
    string path;
    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {
        dfs1(root);

        return path;
    }

    // 序列化
    void dfs1(TreeNode* root) {
        if (!root) path += "#,";
        else {
            path += to_string(root->val) + ',';     // 加 ',' 将每个数间隔,否则出现 123 这种情况不知道是几位数
            dfs1(root->left);
            dfs1(root->right);
        }
    }

    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
        int u = 0;
        return dfs2(data, u);                       // 反序列化, 从 0 开始实现
    }

    // 反序列化
    TreeNode* dfs2(string& data, int& u) {
        if (data[u] == '#') {
            u += 2;
            return NULL;
        } else {
            int k = u;
            while (data[u] != ',') u ++ ;
            auto root = new TreeNode(stoi(data.substr(k, u - k)));
            u ++ ;                                      // 跳过 ','
            root->left = dfs2(data, u);
            root->right = dfs2(data, u);

            return root;
        }
    }
};

层序序列化、反序列化:基于 bfs 迭代。

class Codec {
public:
    string path;
    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {
        bfs1(root);
        return path;
    }

    // 序列化,直接 bfs 记录即可,不需要分层
    void bfs1(TreeNode* root) {
        queue<TreeNode*> q;
        q.push(root);

        while (q.size()) {
            TreeNode* t = q.front(); q.pop();
            if (!t) path += "#,";
            else {
                path += to_string(t->val) + ',';
                q.push(t->left);
                q.push(t->right);
            }
        }
    }

    // 反序列化
    TreeNode* bfs2(string& data) {
        if (data == "#,") return NULL;
        queue<TreeNode*> q;
        int k = 0;
        while (data[k] != ',') k ++ ;
        TreeNode* root = new TreeNode(stoi(data.substr(0, k)));     // root 元素不为空
        k ++ ;                  // 跳过 ','
        q.push(root);

        int i = k;      // 从k位置开始,顺序遍历序列化字符串,i 表示遍历到序列化字符串的位置
        while (q.size()) {      
            TreeNode* t = q.front(); q.pop();
            // 左右节点一定成对出现,不为 '#' 即为数值,则为有效节点
            // 为 '#',则为空节点,需要跳过序列化字符串中的 "#," 两个位置
            // 先左节点
            if (data[i] != '#') {
                int idx = i;
                while (data[idx] != ',') idx ++ ;
                TreeNode* left = new TreeNode(stoi(data.substr(i, idx - i)));
                idx ++ ;
                t->left = left;
                q.push(left);
                i = idx;
            } else i += 2;

            // 再右节点
            if (data[i] != '#') {
                int idx = i;
                while (data[idx] != ',') idx ++ ;
                TreeNode* right = new TreeNode(stoi(data.substr(i, idx - i)));
                idx ++ ;
                t->right = right;
                q.push(right);
                i = idx;
            } else i += 2;
        }

        return root;
    }

    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
        return bfs2(data);
    }
};

以上是关于[H二叉树] lc297. 二叉树的序列化与反序列化(二叉树+前序遍历+中序遍历+面试经典)的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode 297. 二叉树的序列化与反序列化(bfs,二叉树,Java)

LeetCode 297 二叉树的序列化与反序列化[BFS 二叉树] HERODING的LeetCode之路

LeetCode Java刷题笔记—297. 二叉树的序列化与反序列化

[JavaScript 刷题] 树 - 二叉树的序列化与反序列化, leetcode 297

[JavaScript 刷题] 树 - 二叉树的序列化与反序列化, leetcode 297

297. 二叉树的序列化与反序列化(困难)