1.Encode N-ary Tree to Binary Tree
一个多叉树,将其序列化为一个二叉树,并且可以通过该二叉树反序列化为原来的多叉树
思路:
我们可以将该多叉树的每个子节点,全部放置在该节点的左数右边界上,如下图:
我们可以将该节点的所有子节点,放置在该节点的左树右边界上,右树我们不管,可以为null,这样我们就可以将该多叉树序列化成唯一的二叉树,将该步骤反过来就可以将该二叉树还原成原来的多叉树。
代码如下:
public class EncodeNaryTreeToBinaryTree {
public static 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;
}
}
public static class TreeNode{
int val;
TreeNode left;
TreeNode right;
TreeNode(int x){
val = x;
}
}
class Codec{
public TreeNode encode(Node root){
if (root == null){
return null;
}
TreeNode head = new TreeNode(root.val);
head.left = en(root.children);
return head;
}
public TreeNode en (List<Node> childrens){
//定义二叉树当前节点
TreeNode cur = null;
//定义一个头节点,作为左子树右列的头
TreeNode head = null;
for (Node children : childrens) {
TreeNode node = new TreeNode(children.val);
//如果为空,则表示右列还没有节点,我们就new一个
//不为空说明左子树的右列已经有节点了,我们就连下去
if (head == null){
head = node;
}else {
cur.right = node;
}
cur = node;
//递归将孩子序列化成二叉树
cur.left = en(children.children);
}
return head;
}
public Node decode(TreeNode root){
if (root == null){
return null;
}
Node node = new Node(root.val,de(root));
return node;
}
public List<Node> de(TreeNode root){
//新建一个孩子链表
List<Node> children = new LinkedList<>();
while (root != null){
//递归调用生成多叉树的节点
Node node = new Node(root.val,de(root.left));
//将生成的节点添加到链表中
children.add(node);
root = root.right;
}
return children;
}
}
}
2.给定一个二叉树的节点,求出该节点的后续节点
1. 该节点有右子树,该节点的后续节点就是右子树的最左节点。
2.该节点没有右子树,就找该节点的父节点,如果该节点是该父节点的右树,就继续往上,一直到该树是父节点的左树为止,那么该父节点就是该节点的后继节点。
代码如下:
public class NextNode {
public static class Node{
public int value;
public Node left;
public Node right;
public Node parent;
public Node(int data){
this.value = data;
}
}
public static Node getNextNode(Node node){
if (node == null){
return null;
}
if (node.right != null){
return getLeftMost(node.right);
}else { //无右子树
Node parent = node.parent;
while (parent != null && node == parent.right){
node = parent;
parent = node.parent;
}
return parent;
}
}
private static Node getLeftMost(Node node) {
if (node == null){
return null;
}
while (node.left != null){
node = node.left;
}
return node;
}
}
3.判断该树是否是完全二叉树
3.1 什么是完全二叉树?
二叉树的每一层要么是满的,如果不满,那么一定是最后一层不满,并且从左至右依次处于变满的路上的二叉树叫完全二叉树。
那么如何判断该树是否是完全二叉树呢,其实就是上篇文章中的二叉树按层遍历,只不过在遍历过程中需要遵循一些规则。
那么需要遵循什么规则呢?
1 如果一个节点,该节点如果只有右节点而没有左节点,那么就直接返回false
2.在不满足1的前提下,在第一次遇到某个节点的左节点或者右节点不双全的情况下,之后遍历的节点一定都是叶子节点。否则返回false
如果遍历完之后都没返回false,就说明是完全二叉树。
代码如下:
public static Boolean isCBT(Node head){
if (head == null){
return true;
}
Queue<Node> queue = new LinkedList<>();
queue.add(head);
Boolean leaf = false;
Node left = null;
Node right = null;
while (!queue.isEmpty()){
Node poll = queue.poll();
left = poll.left;
right = poll.right;
if (leaf && (left != null || right!= null) || (left== null && right != null)){
return false;
}
if (leaf != null || right != null){
leaf = true;
}
if (left != null){
queue.add(left);
}
if (right != null){
queue.add(right);
}
}
return true;
}
4.返回该树是否是平衡二叉树
4.1 平衡二叉树是指该树的每一颗子树,它的左树的最大高度和右树的最大高度相差的绝对值不超过1。
代码如下:
public static Boolean isBalanceTree(Node head){
if (head == null){
return true;
}
return process(head).isBalance;
}
public static class Info{
boolean isBalance;
int height;
public Info(boolean isBalance,int height){
this.isBalance = isBalance;
this.height = height;
}
}
public static Info process(Node node){
if (node == null){
return new Info(true,0);
}
Info left = process(node.left);
Info right = process(node.right);
boolean isBalance = true;
if (!left.isBalance || !right.isBalance){
isBalance = false;
}
if (Math.abs(left.height - right.height) > 1){
isBalance = false;
}
return new Info(isBalance, Math.max(left.height,right.height)+1);
}
5.返回该树是否是搜索二叉树
5.1 什么是搜索二叉树
对于搜索二叉树的每一个子树,它左子树的最大值小于该节点的值,它右子树的最小值大于该节点的值。
代码如下:
public static boolean isSearchTree(Node head){
if (head == null){
return true;
}
return process(head).isSearch;
}
public static class Info{
boolean isSearch;
int max;
int min;
public Info(boolean isSearch,int max,int min){
this.isSearch = isSearch;
this.max = max;
this.min = min;
}
}
public static Info process(Node node){
if (node == null){
return null;
}
Info left = process(node.left);
Info right = process(node.right);
boolean isSearch = true;
if (left != null && !left.isSearch){
isSearch = false;
}
if (right != null && !right.isSearch){
isSearch = false;
}
int min = node.value;
int max = node.value;
if (left != null){
max = Math.max(left.max,max);
min = Math.min(left.min,min);
}
if (right != null){
max = Math.max(right.max,max);
min = Math.min(right.min,min);
}
if (left != null && left.max >= node.value){
isSearch = false;
}
if (right != null && right.min <= node.value){
isSearch = false;
}
return new Info(isSearch,max,min);
}
6.返回整棵树的最大距离
如何返回?
1.有头结点参与
返回左树高度和右树的高度+1,如果有头结点参与,那么最远的肯定是左树的高度和右树的高度+1;
2.没有头结点参与
返回左树最大距离或者右树最大距离的较大者
代码如下:
public static int maxDistance(Node head){
if (head == null){
return 0;
}
return process(head).maxDistance;
}
public static class Info{
int maxDistance;
int height;
public Info(int maxDistance,int height) {
this.maxDistance = maxDistance;
this.height = height;
}
}
public static Info process(Node node){
if (node == null){
return new Info(0,0);
}
Info left = process(node.left);
Info right = process(node.right);
int height = Math.max(left.height,right.height) + 1;
int p1 = left.maxDistance;
int p2 = right.maxDistance;
int p3 = left.height + right.height + 1;
int maxDistance = Math.max(p1,Math.max(p2,p3));
return new Info(maxDistance,height);
}
7.找到最大的子树是搜索二叉树
通过上文我们已经知道什么是搜索二叉树,该问题是在一个树中,找到最大的搜索二叉树。
public static int maxSearchTree(Node head){
if (head == null){
return 0;
}
return process(head).searchSize;
}
public static class Info{
int size;
int searchSize;
int max;
int min;
public Info(int size,int searchSize,int max,int min){
this.size = size;
this.searchSize = searchSize;
this.max = max;
this.min = min;
}
}
public static Info process(Node node){
if (node == null){
return null;
}
Info left = process(node.left);
Info right = process(node.right);
int size = 1;
int max = node.value;
int min = node.value;
int p1 = -1;
int p2 = -1;
int p3 = -1;
if (left != null){
max = Math.max(left.max,max);
min = Math.min(left.min,min);
size += left.size;
p1 = left.searchSize;
}
if (right != null){
max = Math.max(right.max,max);
min = Math.min(right.min,min);
size += right.size;
p2 = right.searchSize;
}
boolean leftIsSearch = left == null ? true : (left.searchSize == left.size);
boolean rightIsSearch = right == null ? true : (right.searchSize == right.size);
if (rightIsSearch && leftIsSearch){
boolean leftMaxLessNode = left == null ? true : (left.max < node.value);
boolean ringMinMoreNode = right == null ? true : (right.min > node.value);
if (leftMaxLessNode && ringMinMoreNode){
int leftSize = left == null ? 0 : left.size;
int rightSize = right == null ? 0 : right.size;
p3 = leftSize + rightSize + 1;
}
}
return new Info(size,Math.max(p1,Math.max(p2,p3)),max,min);
}
二叉树树形dp题目通用思路总结:
1.假设以X节点为头,假设可以向X左树和右树要任何信息。
2.在上一步假设下,讨论以头节点为X的树,得到答案的可能性(最重要)
3.列出所有的可能性后,确定到底需要向左树和右树要什么样的信息
4.把左树信息和右树信息求全集,就是任何一课树都要返回的信息S
5.递归函数返回S,每一颗子树都这么要求
6.编写代码,在代码中考虑如何把左树的信息和右树的信息整合出整数的信息。