"""
# Definition for a Node.
class Node:
def __init__(self, val=None, children=None):
self.val = val
self.children = children if children is not None else []
class Codec:
def serialize(self, root: 'Node') -> str:
res = []
def dfs(node):
if not node:
return
res.append(str(node.val))
res.append(str(len(node.children)))
for child in node.children:
dfs(child)
dfs(root)
return ' '.join(res)
def deserialize(self, data: str) -> 'Node':
if not data:
return None
tokens = iter(data.split())
def dfs():
val = int(next(tokens))
size = int(next(tokens))
node = Node(val)
for _ in range(size):
node.children.append(dfs())
return node
return dfs()
/*
// Definition for a Node.
class Node {
public:
int val;
vector<Node*> children;
Node() {}
Node(int _val) {
val = _val;
}
Node(int _val, vector<Node*> _children) {
val = _val;
children = _children;
}
};
*/
class Codec {
public:
// Encodes a tree to a single string.
string serialize(Node* root) {
string res;
dfs(root, res);
return res;
}
void dfs(Node* node, string& res) {
if (!node) return;
res += to_string(node->val) + " ";
res += to_string(node->children.size()) + " ";
for (Node* child : node->children) {
dfs(child, res);
}
}
// Decodes your encoded data to tree.
Node* deserialize(string data) {
if (data.empty()) return nullptr;
istringstream iss(data);
return dfs2(iss);
}
Node* dfs2(istringstream& iss) {
int val, size;
iss >> val >> size;
Node* node = new Node(val);
for (int i = 0; i < size; ++i) {
node->children.push_back(dfs2(iss));
}
return node;
}
};
/*
// Definition for a Node.
class Node {
public int val;
public List<Node> children;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, List<Node> _children) {
val = _val;
children = _children;
}
};
*/
class Codec {
// Encodes a tree to a single string.
public String serialize(Node root) {
StringBuilder sb = new StringBuilder();
dfs(root, sb);
return sb.toString();
}
private void dfs(Node node, StringBuilder sb) {
if (node == null) return;
sb.append(node.val).append(" ");
sb.append(node.children.size()).append(" ");
for (Node child : node.children) {
dfs(child, sb);
}
}
// Decodes your encoded data to tree.
public Node deserialize(String data) {
if (data.isEmpty()) return null;
String[] tokens = data.split(" ");
int[] idx = new int[]{0};
return dfs2(tokens, idx);
}
private Node dfs2(String[] tokens, int[] idx) {
int val = Integer.parseInt(tokens[idx[0]++]);
int size = Integer.parseInt(tokens[idx[0]++]);
Node node = new Node(val, new ArrayList<>());
for (int i = 0; i < size; ++i) {
node.children.add(dfs2(tokens, idx));
}
return node;
}
}
/**
* // Definition for a Node.
* function Node(val, children) {
* this.val = val;
* this.children = children || [];
* };
*/
var Codec = function() {};
Codec.prototype.serialize = function(root) {
let res = [];
function dfs(node) {
if (!node) return;
res.push(node.val);
res.push(node.children.length);
for (let child of node.children) {
dfs(child);
}
}
dfs(root);
return res.join(' ');
};
Codec.prototype.deserialize = function(data) {
if (!data) return null;
let tokens = data.split(' ');
let idx = 0;
function dfs() {
let val = parseInt(tokens[idx++]);
let size = parseInt(tokens[idx++]);
let node = new Node(val, []);
for (let i = 0; i < size; ++i) {
node.children.push(dfs());
}
return node;
}
return dfs();
};
The problem asks you to design an algorithm to serialize and deserialize an N-ary tree. An N-ary tree is a rooted tree in which each node can have up to N
children (not just two, as in a binary tree).
You must implement two functions:
serialize(root)
: Converts the tree to a string representation.deserialize(data)
: Converts the string representation back to the original tree structure.Constraints:
val
and a list of children
.At first glance, the problem is similar to serializing and deserializing a binary tree, but with the added complexity that each node can have any number of children.
For binary trees, we often use pre-order or level-order traversal, using markers (like #
or null
) for missing children. For N-ary trees, we need a way to know how many children each node has, since there could be zero or many.
The brute-force way would be to represent the tree in a nested format (like JSON), but that's verbose and less efficient. Instead, we can use a compact pre-order traversal where, for each node, we record:
The main challenge is ensuring that the serialization format contains enough information to reconstruct the tree exactly, even when nodes have zero children.
Let's break down the algorithm step-by-step:
val
and the number of children to the result.val
and its number of children.children
list.This approach is efficient, simple, and works for any N-ary tree structure.
Let's walk through a concrete example:
Suppose we have the following N-ary tree:
1 / | \ 3 2 4 / \ 5 6
The serialized string becomes:
1 3 3 2 5 0 6 0 2 0 4 0
As we process, we reconstruct the original tree structure exactly.
Brute-force Approach:
The solution is optimal in both time and space for this problem.
To serialize and deserialize an N-ary tree, we use a pre-order traversal, recording each node's value and the number of its children. This compact representation allows us to reconstruct the tree exactly, regardless of its shape or the number of children per node. The approach is simple, efficient, and generalizes well to any N-ary tree. The key insight is to include the number of children in the serialization, enabling correct parsing during deserialization.