[H二叉树] lc297. 二叉树的序列化与反序列化(二叉树+前序遍历+中序遍历+面试经典)
Posted Ypuyu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[H二叉树] lc297. 二叉树的序列化与反序列化(二叉树+前序遍历+中序遍历+面试经典)相关的知识,希望对你有一定的参考价值。
1. 题目来源
相同:[剑指-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