leetcode:428. 序列化和反序列化 N 叉树(会员题)
lintcode:1532 · 序列化和反序列N叉树
题目
序列化是将一个数据结构或对象转换成比特流的过程,以便将其存储在文件或内存缓冲区中,或通过网络连接链路传输,以便稍后在同一或另一计算机环境中重建。
设计一个算法来序列化和反序列化一个 N 叉树。一棵 N 叉树是一棵有根树,其中每个节点的子节点不超过 N 个。序列化/反序列化算法的实现方式没有限制。您只需要确保N叉树可以序列化为字符串,并且该字符串可以反序列化为原始树结构。
例如,你可以序列化如下的 3 叉树
为 [1 [3[5 6] 2 4]]
。你不一定要遵循这种格式,发挥创意,自己想出不同的方法。
示例 1:
输入:{1,3,2,4#2#3,5,6#4#5#6}
输出:{1,3,2,4#2#3,5,6#4#5#6}
解释:如上图
输入:{1,3,2#2#3}
输出:{1,3,2#2#3}
解释:
1
/ \
3 2
解答 & 代码
和[困难] 297. 二叉树的序列化与反序列化基本一致,也可以通过先序遍历来序列化,只是 N 叉树的子节点数量不定,因此在序列化的时候,还需要存储每个节点的子节点数量
/**
* Definition for Directed graph.
* struct DirectedGraphNode {
* int label;
* vector<DirectedGraphNode *> neighbors;
* DirectedGraphNode(int x) : label(x) {};
* };
*/
// 通过括号确定层级和节点的父子关系
class Solution {
private:
// 递归序列化 N 叉树(先序遍历),结果存储在 result
void dfsSerialize(DirectedGraphNode* root, string& result)
{
if(root == nullptr) // 递归结束条件:空节点
{
result += "N ";
return;
}
// 先序位置
result += to_string(root->label); // 存储当前节点的值
result += " " + to_string(root->neighbors.size()) + " "; // 存储当前节点的子节点数目
// 递归遍历所有子节点
for(int i = 0; i < root->neighbors.size(); ++i)
dfsSerialize(root->neighbors[i], result);
}
// 递归反序列化 N 叉树(先序遍历)
UndirectedGraphNode* dfsDeserialize(istringstream& data)
{
string val;
data >> val;
if(val == "N") // 递归结束条件:空节点
return nullptr;
// 先序位置
UndirectedGraphNode* root = new UndirectedGraphNode(stoi(val)); // 建立当前节点
data >> val;
int childCnt = stoi(val); // 当前节点的子节点数目
// 递归遍历所有子节点
for(int i = 0; i < childCnt; ++i)
{
UndirectedGraphNode* child = dfsDeserialize(data);
root->neighbors.push_back(child);
}
return root;
}
public:
string serialize(vector<DirectedGraphNode*> &nodes) {
string result;
if(nodes.size() == 0)
return "N ";
dfsSerialize(nodes[0], result);
// cout << result << endl;
return result;
}
UndirectedGraphNode* deserialize(string &data) {
// cout << data << endl;
istringstream istr(data);
return dfsDeserialize(istr);
}
};
复杂度分析:设 N 叉树节点数为 m
- 时间复杂度 O(m):遍历每个节点
- 空间复杂度 O(log m):递归栈深度 = 树深度
执行结果:
执行结果:通过
执行用时:41 ms, 在所有 C++ 提交中击败了 76.09% 的用户
内存消耗:5.47 MB, 在所有 C++ 提交中击败了 76.09% 的用户