二叉树的递归套路可以解决绝大多数的二叉树问题尤其是树形dp问题,本质是利用递归遍历二叉树的便利性
问题一:
给定一颗二叉树的头结点head,返回这颗二叉树是不是平衡二叉树
满足条件:①左树是平衡的;②右树是平衡的;③左树与右树的高度差不超过1;
package tree;
public class IsBalanced {
public static class Node{
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value=data;
}
}
public static boolean isBalanced(Node head) {
return process(head).isBalanced;
}
//左右要求一样,info信息返回的结构体(一共返回两个信息)
public static class Info{
public boolean isBalanced;
public int height;
public Info(boolean b,int h) {
isBalanced=b;
height=h;
}
}
//Node X:以X为头的树
public static Info process(Node X) {
if(X==null) {
return new Info(true,0);
}
Info leftInfo=process(X.left);
Info rightInfo=process(X.right);
int height=Math.max(leftInfo.height, rightInfo.height)+1;
boolean isBalanced=true;
if(!leftInfo.isBalanced || !rightInfo.isBalanced || Math.abs(leftInfo.height-rightInfo.height)>1) {
isBalanced=false;
}
return new Info(isBalanced, height);
}
public static void main(String[] args) {
}
}
问题二:
给定一颗二叉树的头结点head,任何两个节点之间都存在距离,返回整颗二叉树的最大距离
分为两类:
①最大距离与当前节点无关,则最大距离=max{左树最大距离,右树最大距离}
②最大距离与当前节点有关,即左树最远的点到右树最远的点(左树高度+1+右树高度)
要求:左树返回离自己最大的距离及高度,右树返回离自己最大的距离及高度
package tree;
public class MaxDistance {
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
public static int maxDistance(Node head) {
return process(head).maxDistance;
}
public static class Info {
public int maxDistance;
public int height;
public Info(int dis, int h) {
maxDistance = dis;
height = h;
}
}
public static Info process(Node X) {
if (X == null) {
return new Info(0, 0);
}
Info leftInfo = process(X.left);
Info rightInfo = process(X.right);
int height = Math.max(leftInfo.height, rightInfo.height) + 1;
int maxDistance = Math.max(
Math.max(leftInfo.maxDistance, rightInfo.maxDistance),
leftInfo.height + rightInfo.height + 1);
return new Info(maxDistance, height);
}
public static void main(String[] args) {
}
}
问题三:
定个一颗二叉树的头结点head,返回这颗二叉树中最大的二叉搜索子树的头结点
①与当前节点无关
②与当前节点有关,即当前节点的左树和右树整体都是搜索二叉树,且左树的最大值小于X,右树的最小值大于X
要求:左树的最大子搜索二叉树的大小;左树整体是不是搜索二叉树,左树上的最大值;
右树的最大子搜索二叉树的大小;右树整体是不是搜索二叉树,右树上的最小值;
故需要的信息即是要求的全集:最大子搜索二叉树的大小;是不是搜索二叉树;最大值,最小值
package tree;
public class MaxSubBSTSize {
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
public static int maxSubBSTSize(Node head) {
if(head==null) {
return 0;
}
return process(head).maxSubBSTSize;
}
public static class Info {
public boolean isAllBST;
public int maxSubBSTSize;
public int max;
public int min;
public Info(boolean is,int size,int mi,int ma) {
isAllBST=is;
maxSubBSTSize=size;
max=ma;
min=mi;
}
}
public static Info process(Node X) {
if (X == null) {
return null;
}
Info leftInfo = process(X.left);
Info rightInfo = process(X.right);
int min=X.value;
int max=X.value;
if(leftInfo!=null) {
min=Math.min(min, leftInfo.min);
max=Math.max(max, leftInfo.max);
}
if(rightInfo!=null) {
min=Math.min(min, rightInfo.min);
max=Math.max(max, rightInfo.max);
}
int maxSubBSTSize=0;
if(leftInfo!=null) {
maxSubBSTSize=leftInfo.maxSubBSTSize;
}
if(rightInfo!=null) {
maxSubBSTSize=Math.max(maxSubBSTSize,rightInfo.maxSubBSTSize);
}
boolean isAllBST=false;
if(
//左树整体需要是搜索二叉树
(leftInfo==null?true:leftInfo.isAllBST)
&&
(rightInfo==null?true:rightInfo.isAllBST)
&&
//左树最大值<x
(leftInfo==null?true:leftInfo.max<X.value)
&&
(rightInfo==null?true:rightInfo.min>X.value)
) {
maxSubBSTSize=
(leftInfo==null?0:leftInfo.maxSubBSTSize)
+(rightInfo==null?0:rightInfo.maxSubBSTSize)
+1;
isAllBST=true;
}
return new Info(isAllBST,maxSubBSTSize,min,max);
}
public static void main(String[] args) {
}
}
问题四:
派对的最大快乐值问题
员工信息的定义如下:
class Employee{
public int happy;// 这名员工可以带来的快乐值
List<Employee> subordinates;// 这名员工有哪些直接的下级
}
公司要来办party,你可以决定哪些员工来,哪些员工不来,规则:
1、 如果某个员工来了,那么这个员工的所有直接下级都不能来
2、 派对的整体快乐值是所有到场员工的快乐值的累加
3、 你的目标是让排队的整体快乐值尽量的大
给定一颗多叉树的头结点boss,请返回排队的最大快乐值
【分析】
①X不来:0+max{a来,a不来}+max{b来,b不来}+maxc来,c不来}(假设X有a,b,c三个直接下级)
②X来:X的快乐值+X某个子树整棵树的的最大快乐值
要求:头节点X来时的最大快乐值;头节点X不来时的最大快乐值
package tree;
import java.util.ArrayList;
import java.util.List;
public class MaxHappy {
public static class Employee {
public int happy;
public List<Employee> nexts;
public Employee(int h) {
happy = h;
nexts = new ArrayList<>();
}
}
public static int maxHappy(Employee head) {
Info allInfo = process(head);
return Math.max(allInfo.no, allInfo.yes);
}
public static class Info {
public int no;
public int yes;
public Info(int n, int y) {
no = n;
yes = y;
}
}
public static Info process(Employee x) {
if (x.nexts.isEmpty()) {
return new Info(x.happy, 0);
}
int no = 0;
int yes = x.happy;
for (Employee next : x.nexts) {
Info nextInfo = process(next);
no += Math.max(nextInfo.no, nextInfo.yes);
yes += nextInfo.no;
}
return new Info(no, yes);
}
public static void main(String[] args) {
}
}
总结:
- 假设以X节点为头,假设可以向X左树和右树要任何信息
- 在上一步的假设下,讨论以X为头结点的树,得到答案的可能性(最重要),常见分类是与X无关的答案,与X有关的答案
- 列出所有可能性后,确定到底需要向左树和右树要什么样的信息
- 把左树信息和右树信息求全集,就是任何一颗子树都需要返回的信息S
- 递归函数都返回S,每颗子树都这么要求
- 写代码,在代码中考虑如何把左树信息和右树信息整合出整棵树的信息