一、题目
设计一个算法,可以将 N 叉树编码为二叉树,并能将该二叉树解码为原 N 叉树。 一个 N 叉树是指每个节点都有不超过 N 个孩子节点的有根树。 类似地,一个二叉树是指每个节点都有不超过 2 个孩子节点的有根树。 你的编码 / 解码的算法的实现没有限制,你只需要保证一个 N 叉树可以编码为二叉树且该二叉树可以解码回原始 N 叉树即可。
例如,你可以将下面的 3-叉 树以该种方式编码:
注意,上面的方法仅仅是一个例子,可能可行也可能不可行。 你没有必要遵循这种形式转化,你可以自己创造和实现不同的方法。
注意: N 的范围在 [1, 1000] 不要使用类成员 / 全局变量 / 静态变量来存储状态。 你的编码和解码算法应是无状态的。
二、代码
/**
* 将N叉树的每个节点的所有孩子节点,都转换成二叉树的左子树右边界,即可完成N叉树到二叉树的转换
*/
class Solution {
// Encodes an n-ary tree to a binary tree.
// 将N叉树转换为二叉树
public TreeNode encode(Node root) {
// 根节点为空,直接返回null
if (root == null) {
return null;
}
// 将N叉树根节点转换为二叉树节点
TreeNode head = new TreeNode(root.val);
// 将N叉树所有的孩子节点都添加到二叉树的左子树的右边界上,通过递归去实现
head.left = en(root.children);
return head;
}
// 是一个深度优先递归,先递归到最底,在向上返回时再进行每一层递归栈的操作
private TreeNode en(List<Node> children) {
// 创建二叉树节点,表示左子树的根节点
TreeNode head = null;
// 遍历时的当前节点
TreeNode cur = null;
// 遍历N叉树节点所有的孩子节点,将所有的孩子都往右边界上挂
for (Node child : children) {
// 将N叉树节点转换为孩子节点
TreeNode tNode = new TreeNode(child.val);
// 如果左子树根节点为空,说明这是第一轮循环,还没有任何N叉树孩子节点添加到左子树上,这里就初始化左子树根节点
if (head == null) {
// 将当前N叉树孩子节点设置为二叉树左子树根节点
head = tNode;
} else {
// 这里cur是上一次循环到的节点,我们要把所有的子孩子都加到有边界,所以将本次循环到的子孩子tNode追加到上一次循环到的节点的右子节点处
cur.right = tNode;
}
// cur指向本次循环到的孩子节点
cur = tNode;
// 递归去继续转换本次遍历到的节点的孩子,这里就是深度优先递归,先递归到最底,然后在向上返回的过程中处理余下的孩子节点
cur.left = en(child.children);
}
return head;
}
// Decodes your binary tree to an n-ary tree.
// 将二叉树转换为N叉树
public Node decode(TreeNode root) {
if (root == null) {
return null;
}
// 调用递归函数,将二叉树转换为N叉树
return new Node(root.val, de(root.left));
}
// 是一个深度优先递归
public List<Node> de(TreeNode root) {
// 创建存放孩子节点的List<Node>
List<Node> children = new ArrayList<>();
// 将每一个节点的左子树上所有右边界的节点全部添加到List中,当遍历到null则说明已经将所有的孩子节点添加进List了
while (root != null) {
// 创建N叉树节点,并且调用递归函数去转换本次循环到的节点的左子树
Node cur = new Node(root.val, de(root.left));
// 将N叉树节点添加到List中
children.add(cur);
// 继续向右边界节点遍历
root = root.right;
}
// 返回本层节点的List
return children;
}
}
三、解题思路
其实这道题就是N叉树如何通过二叉树来序列化、并完成反序列化的问题,本质就是实现将N叉树转换为二叉树,二叉树转换为N叉树的过程
转换原则:多叉树任何X所有孩子节点放在X的左树右边界,右树根本不用。