将 N 叉树编码为二叉树
将 N 叉树编码为二叉树
作者:Grey
原文地址:
题目描述
将一棵n叉树编码为一棵二叉树,并对二叉树进行解码,得到原始的n叉树。 n叉树是一棵有根树,其中每个节点的子树不超过n个。 类似地,二叉树是一棵有根树,其中每个节点的子树不超过2个。 编码/解码算法的工作方式不受限制。 您只需要确保一个n叉树可以被编码为一个二叉树,并且这个二叉树可以被解码为原始的n叉树结构。
题目链接:LintCode 1530 · Encode N-ary Tree to Binary Tree
一棵 N 叉树的示例如下

二叉树的数据结构如下
class TreeNode {
public int val;
public TreeNode left, right;
public TreeNode(int val) {
this.val = val;
this.left = this.right = null;
}
}
N 叉树的数据结构如下
class UndirectedGraphNode {
int label;
List<UndirectedGraphNode> neighbors;
UndirectedGraphNode(int x) {
label = x;
neighbors = new ArrayList<UndirectedGraphNode>();
}
}
每个节点有属于自己的 label 值,也有若干个孩子节点,即List<UndirectedGraphNode> neighbors。
我们需要实现如下两个方法
// N 叉树编码成 二叉树
TreeNode encode(UndirectedGraphNode root)
// 二叉树编码成 N 叉树
UndirectedGraphNode decode(TreeNode root)
主要思路
N 叉树编码成二叉树的方法是将 N 叉树中每个节点的子节点转换成自己左树的右边界或者右树的左边界,示例图如下

二叉树编码成 N 叉树的方法就是把每个节点的左树右边界存到一个 List 里面,作为这个节点的子节点列表即可,就是上述示例图的逆过程。
N 叉树编码成二叉树的过程就是一个深度优先遍历,首先
TreeNode head = new TreeNode(root.label);
表示二叉树的根节点就是 N 叉树的根节点,
然后将根节点的孩子节点,调用递归,进行深度优先遍历,代码如下
// 将某个节点的孩子节点挂在其右树的左边界上
// 将 N 叉树的根节点的孩子节点做深度优先遍历
// 并将其挂在根节点的右树上
head.right = en(root.neighbors);
// 深度优先遍历
private TreeNode en(List<UndirectedGraphNode> neighbors) {
TreeNode c = null;
TreeNode head = null;
for (UndirectedGraphNode neighbor : neighbors) {
TreeNode node = new TreeNode(neighbor.label);
if (head == null) {
// 头节点为空,建出来
head = node;
} else {
// 否则挂在当前节点的右树的左边界上
c.left = node;
}
c = node;
c.right = en(neighbor.neighbors);
}
return head;
}
将二叉树转换成 N 叉树的逻辑如下:
首先
UndirectedGraphNode node = new UndirectedGraphNode(root.val);
表示:N 叉树的根节点也是二叉树的根节点。
接着调用递归,将二叉树的右树构造出 N 叉树当前节点的孩子节点。
// 将二叉树的右树构造出 N 叉树当前节点的孩子节点
node.neighbors = de(root.right);
public ArrayList<UndirectedGraphNode> de(TreeNode root) {
ArrayList<UndirectedGraphNode> children = new ArrayList<>();
while (root != null) {
UndirectedGraphNode cur = new UndirectedGraphNode(root.val);
cur.neighbors = de(root.right);
children.add(cur);
root = root.left;
}
return children;
}
其中 while 循环中就是不断的把当前节点的左树右边界加入到一个 List 中,最后返回。
完整代码如下
public class Solution {
public UndirectedGraphNode decode(TreeNode root) {
if (root == null) {
return null;
}
UndirectedGraphNode node = new UndirectedGraphNode(root.val);
node.neighbors = de(root.right);
return node;
}
public ArrayList<UndirectedGraphNode> de(TreeNode root) {
ArrayList<UndirectedGraphNode> children = new ArrayList<>();
while (root != null) {
UndirectedGraphNode cur = new UndirectedGraphNode(root.val);
cur.neighbors = de(root.right);
children.add(cur);
root = root.left;
}
return children;
}
// 每个子节点转换成自己左树的右边界或者右树的左边界 + 深度优先遍历
// 编码
public TreeNode encode(UndirectedGraphNode root) {
if (root == null) {
return null;
}
TreeNode head = new TreeNode(root.label);
// 右树的左边界
head.right = en(root.neighbors);
return head;
}
private TreeNode en(List<UndirectedGraphNode> neighbors) {
TreeNode c = null;
TreeNode head = null;
for (UndirectedGraphNode neighbor : neighbors) {
TreeNode node = new TreeNode(neighbor.label);
if (head == null) {
// 头节点为空,建出来
head = node;
} else {
// 否则挂在当前节点的右树的左边界上
c.left = node;
}
c = node;
c.right = en(neighbor.neighbors);
}
return head;
}
}
本文涉及到的所有图例见:二叉树与N叉树的互相转换
更多
将 N 叉树编码为二叉树的更多相关文章
- [LeetCode] Encode N-ary Tree to Binary Tree 将N叉树编码为二叉树
Design an algorithm to encode an N-ary tree into a binary tree and decode the binary tree to get the ...
- 剑指offer-面试题27-二叉树的镜像-二叉树
/* 题目:输入一个二叉树,输出该函数的镜像. */ /* 思路: 基础条件:树为空,或只有一个节点. 其它:递归交换二叉树的左右子树. */ void Mirror(TreeNode *pRoot) ...
- leetcode难题
4 寻找两个有序数组的中位数 35.9% 困难 10 正则表达式匹配 24.6% 困难 23 合并K个排序链表 47.4% 困难 25 K ...
- [数据结构与算法]哈夫曼(Huffman)树与哈夫曼编码
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- POJ 1240 Pre-Post-erous! && East Central North America 2002 (由前序后序遍历序列推出M叉树的种类)
题目链接 问题描述 : We are all familiar with pre-order, in-order and post-order traversals of binary trees. ...
- POJ 1240 Pre-Post-erous! && East Central North America 2002 (由前序后序遍历序列推出M叉树的种类)
题目链接:http://poj.org/problem?id=1240 本文链接:http://www.cnblogs.com/Ash-ly/p/5482520.html 题意: 通过一棵二叉树的中序 ...
- C#数据结构-线索化二叉树
为什么线索化二叉树? 对于二叉树的遍历,我们知道每个节点的前驱与后继,但是这是建立在遍历的基础上,否则我们只知道后续的左右子树.现在我们充分利用二叉树左右子树的空节点,分别指向当前节点的前驱.后继,便 ...
- leetcode_二叉树篇_python
主要是深度遍历和层序遍历的递归和迭代写法. 另外注意:因为求深度可以从上到下去查 所以需要前序遍历(中左右),而高度只能从下到上去查,所以只能后序遍历(左右中). 所有题目首先考虑root否是空.有的 ...
- [Algorithm & NLP] 文本深度表示模型——word2vec&doc2vec词向量模型
深度学习掀开了机器学习的新篇章,目前深度学习应用于图像和语音已经产生了突破性的研究进展.深度学习一直被人们推崇为一种类似于人脑结构的人工智能算法,那为什么深度学习在语义分析领域仍然没有实质性的进展呢? ...
随机推荐
- python中的标识符和保留字
保留字,有一些单词被赋予了特定的意义,这些单词不能作为对象的名字 想要快速获取python中的关键字可以通过以下的程 序来快速实现 import keyword print(keyword.kwlis ...
- Mpvue1.0+Python3.7+Django2.0.4实现微信小程序的支付功能
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_112 其实微信支付有很多种形式,刷脸,扫码,APP支付,小程序支付等,这边只说明小程序支付的实现,不过原理上都大同小异. 首先,需 ...
- Odoo14 ir.actions.act_window
xml声明 1 <record id="res_company_user_action" model="ir.actions.act_window"> ...
- 【freertos】013-任务通知及其实现细节
前言 参考: https://www.freertos.org/RTOS-task-notifications.html 原文:https://www.cnblogs.com/lizhuming/p/ ...
- Three---面向对象与面向过程/属性和变量/关于self/一些魔法方法的使用/继承/super方法/多态
python的面向对象 面向对象与面向过程 面向过程 面向过程思想:需要实现一个功能的时候,看重的是开发的步骤和过程,每一个步骤都需要自己亲力亲为,需要自己编写代码(自己来做) 面向对象 面向对象的三 ...
- 一文搞懂│mysql 中的备份恢复、分区分表、主从复制、读写分离
目录 mysql 的备份和恢复 mysql 的分区分表 mysql 的主从复制读写分离 mysql 的备份和恢复 创建备份管理员 创建备份管理员,并授予管理员相应的权限 备份所需权限:select,r ...
- Reader和Writer区别final.finally.finalize区别
Reader和Writer是字符操作流,Writer是输出的,而Reader是输入的. 首先找到一个文件,比如:File file=new File("."+File.separa ...
- Vim配置文件-详解(.vimrc)
Vim配置文件的作用 Vim启动时,会根据配置文件(.vimrc)来设置 Vim,因此我们可以通过此文件来定制适合自己的 Vim Vim分类 系统Vim配置文件/etc/vimrc 所有系统用户在启动 ...
- Java八股文纯享版——篇①:Java基础
注: 1.笔记为个人归纳整理,尽力保证准确性,如有错误,恳请指正 2.写文不易,转载请注明出处 3.本文首发地址 https://blog.leapmie.com/archives/b8fe0da9/ ...
- flutter系列之:用来管理复杂状态的State详解
目录 简介 StatefuWidget和State State的生命周期 总结 简介 Flutter的基础是widget,根据是否需要跟用户进行交互,widget则可以分为StatelessWidge ...