题目
链接:https://leetcode-cn.com/problems/serialize-and-deserialize-binary-tree
序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。
请设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。
示例
你可以将以下二叉树:
1
/ \
2 3
/ \
4 5
序列化为 "[1,2,3,null,null,4,5]"
提示: 这与 LeetCode 目前使用的方式一致,详情请参阅 LeetCode 序列化二叉树的格式。你并非必须采取这种方式,你也可以采用其他的方法解决这个问题。
说明
不要使用类的成员 / 全局 / 静态变量来存储状态,你的序列化和反序列化算法应该是无状态的。
代码模板
/**
* 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 {
public:
// Encodes a tree to a single string.
string serialize(TreeNode* root) {
}
// Decodes your encoded data to tree.
TreeNode* deserialize(string data) {
}
};
// Your Codec object will be instantiated and called as such:
// Codec codec;
// codec.deserialize(codec.serialize(root));
题解
思路
感觉最大的难点是分割字符串和删除多于的null。如果用C#、Java之类的,有强大的字符串操作函数,肯定写起来非常快。
无论是序列化还是反序列化,我们都可以使用层次遍历的方法。
反序列化中,我们先顺序生成所有节点,并放入一个数组。由于每个非空节点都有两个子节点(包括空节点),使用prevLevelTwiceIndex / 2
记录当前节点的父节点索引。如果prevLevelTwiceIndex / 2
对应的父节点为空,我们需要增加prevLevelTwiceIndex
,直到prevLevelTwiceIndex / 2
的值有效。
代码
class Codec
{
public:
string serialize(TreeNode* root)
{
const string null = "null,";
string mid;
queue<TreeNode*> q;
q.push(root);
while (q.empty() == false)
{
auto node = q.front();
q.pop();
if (node == nullptr)
{
mid += null;
}
else
{
mid += to_string(node->val) + ",";
q.push(node->left);
q.push(node->right);
}
}
int length = mid.length();
while (length >= null.size())
{
bool failed = false;
int midStart = length - null.size();
for (int i = null.size() - 1; i >= 0; --i)
{
if (mid[midStart + i] != null[i])
{
failed = true;
break;
}
}
if (failed)
{
break;
}
length -= null.size();
}
if (length != mid.size())
{
mid = mid.substr(0, length);
}
if (mid.empty() == false)
{
mid = mid.substr(0, mid.size() - 1);
}
return "[" + mid + "]";
}
TreeNode* deserialize(string data)
{
data = data.substr(1, data.size() - 2);
vector<TreeNode*> nodes;
string::size_type prev_pos = 0;
string::size_type pos = 0;
while ((pos = data.find(',', pos)) != string::npos)
{
string sub = data.substr(prev_pos, pos - prev_pos);
++pos;
prev_pos = pos;
if (sub == "null")
{
nodes.push_back(nullptr);
}
else
{
nodes.push_back(new TreeNode(stoi(sub)));
}
}
string last = data.substr(prev_pos);
if (last.empty() == false)
{
if (last == "null")
{
nodes.push_back(nullptr);
}
else
{
nodes.push_back(new TreeNode(stoi(last)));
}
}
int prevLevelTwiceIndex = 0;
for (int i = 1; i < nodes.size(); ++i)
{
while (nodes[prevLevelTwiceIndex / 2] == nullptr)
{
++prevLevelTwiceIndex;
}
if (prevLevelTwiceIndex % 2 == 0)
{
nodes[prevLevelTwiceIndex / 2]->left = nodes[i];
}
else
{
nodes[prevLevelTwiceIndex / 2]->right = nodes[i];
}
++prevLevelTwiceIndex;
}
return nodes.empty() ? nullptr : nodes.front();
}
};