传送门
题目要求序列化和反序列化一颗树,先抛开树结点的值,先解决如何确定一颗树的结构这个问题?第一时间想到的方法是用先中序或者是中后序的遍历结果来确定一棵树。再看看题目的限制,树的大小是1e4,结点值是1e3,最坏情况空间和时间复杂度是1e7级别的,勉强可行。再来思考如何确定每个节点的值这一问题,因为可能有重复的值,所以要正确储存一颗树的结构和值,需要对原树进行一点处理。具体方法如下:
序列化
用先序遍历的顺序结果对每一个节点进行重新赋值。在先序遍历的同时将节点上的原值存在一个字符串中。之后再进行中序遍历,储存中序遍历的结果在字符串中,有了这两个字符串即可进行反序列化。
反序列化
将上述两个字符串从data中分离出来,处理出先序遍历的结果和中序遍历的结果就可以用这题的方法得到结果105. 从前序与中序遍历序列构造二叉树。
具体实现:
class Codec {
public:
string mid,val;
int tot = 0;
string trans(int nn){// 将数字转为字符串要记得加入分隔符
int n = abs(nn);
string res = "";
while(n){
res += (n%10+'0');
n /= 10;
}
if(nn < 0) res += '-';
if(res.empty()) res += '0';
reverse(res.begin(),res.end());
res += '.';
return res;
}
void dfsmid(TreeNode *now){ // 中序遍历
if(now == NULL) return;
dfsmid(now->left);
mid += trans(now->val);
dfsmid(now->right);
}
void dfspre(TreeNode *now){ // 先序遍历
if(now == NULL) return;
val += trans(now->val);
now->val = tot++;
dfspre(now->left);
dfspre(now->right);
}
// Encodes a tree to a single string.
string serialize(TreeNode* root) {
if(root == NULL) return "";
dfspre(root);
dfsmid(root);
return mid + ',' + val;
}
vector<int> inorder;
vector<int> preorder;
vector<int> a;
void solve(TreeNode *now,int l1,int r1,int l2,int r2){
now->val = a[preorder[l2]];
int pos = l1;
for(int i = l1;i <= r1;++ i){
if(preorder[l2] == inorder[i]){
pos = i;
break;
}
}
if(l1 == r1) return;
if(pos != l1){
now->left = new TreeNode();
solve(now->left,l1,pos-1,l2+1,l2+pos-l1);
}
if(pos != r1){
now->right = new TreeNode();
solve(now->right,pos+1,r1,l2+pos-l1+1,r2);
}
}
// Decodes your encoded data to tree.
TreeNode* deserialize(string data) {
if(data.empty()) return NULL;
bool flag = true,postive = true;
int val = 0;
int tot = 0;
for(auto x:data){
if(x == ',') flag = false;
else if(x == '.'){
if(!postive) val = -val;
if(flag){
inorder.push_back(val);
preorder.push_back(tot++);
}else{
a.push_back(val);
}
val = 0;
postive = true;
}
else if(x == '-'){
postive = false;
}else{
val = val*10+x-'0';
}
}
int r = inorder.size();
TreeNode *root = new TreeNode();
solve(root,0,r-1,0,r-1);
return root;
}
};