⭐️前言⭐️
本篇文章旨在将二叉树中的树形dp问题模板化,借助信息体传递的方式,通解树形dp问题。
🍉欢迎点赞 👍 收藏 ⭐留言评论 📝私信必回哟😁
🍉博主将持续更新学习记录收获,友友们有任何问题可以在评论区留言
🍉博客中涉及源码及博主日常练习代码均已上传GitHub
📍内容导读📍
- 🍅递归套路
- 🍅判断二叉树是不是平衡二叉树
- 🍅判断二叉树是不是搜索二叉树
- 🍅二叉树最大直径
- 🍅判断二叉树是不是满二叉树
- 🍅最大二叉搜索树
- 🍅完全二叉树判断套路版
- 🍅最大二叉搜索树的头节点
- 🍅最低公共祖先
- 🍅派对的最大快乐值
🍅递归套路
介绍二叉树的递归套路
1)假设以X节点为头,假设可以向X左树和X右树要任何信息
2)在上一步的假设下,讨论以X为头节点的树,得到答案的可能性(最重要)
3)列出所有可能性后,确定到底需要向左树和右树要什么样的信息
4)把左树信息和右树信息求全集,就是任何一棵子树都需要返回的信息S
5)递归函数都返回S,每一棵子树都这么要求
6)写代码,在代码中考虑如何把左树的信息和右树信息整合出整棵树的信息
🍅判断二叉树是不是平衡二叉树
题目:
给定一棵二叉树的头节点head,返回这棵二叉树是不是平衡二叉树
题解思路:
对于任一节点X,满足以下三个条件,才能保证这棵二叉树是平衡二叉树。
1)X的左树是平衡二叉树
2)X的右树是平衡二叉树
3)|X的左树高度-右树高度|<2
所以需要定义信息体,包含以节点X为头节点的树是否平,以及它的高度两个信息。
代码实现:
public class IsBalanced {
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int value) {
this.value = value;
}
}
public static boolean isBalanced(Node head) {
return process(head).isBalanced;
}
public static class Info {
public boolean isBalanced;
public int height;
public Info(boolean isBalanced, int height) {
this.isBalanced = isBalanced;
this.height = height;
}
}
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) {
isBalanced=false;
}
if(Math.abs(leftInfo.height- rightInfo.height)>1) {
isBalanced=false;
}
return new Info(isBalanced,height);
}
}
🍅判断二叉树是不是搜索二叉树
题目:
给定头节点,判断是不是搜索二叉树
题解思路:
每一棵子树,左子树的所有值都比头节点的值小,右子树的所有值都比头节点的值大。
(中序遍历是有序的)
信息体需要包含以下信息:
1、是否是二叉搜索树
2、树上的最大值
3、树上的最小值
判断:
以X为头节点的树
1、左子树是否是搜索二叉树
2、右子树是否是搜索二叉树
3、左子树最大值是否小于X.val
4、右子树最小值是否大于X.val
代码实现:
public class IsBST {
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int value) {
this.value = value;
}
}
public static class Info {
public boolean isBST;
public int max;
public int min;
public Info(boolean isBST, int max, int min) {
this.isBST = isBST;
this.max = max;
this.min = min;
}
}
public static boolean isBST(Node head) {
if(head==null) {
return true;
}
return process(head).isBST;
}
public static Info process(Node x) {
if(x==null) return null;
Info leftInfo=process(x.left);
Info rightInfo=process(x.right);
int max=x.value;
if (leftInfo != null) {
max = Math.max(max, leftInfo.max);
}
if (rightInfo != null) {
max = Math.max(max, rightInfo.max);
}
int min = x.value;
if (leftInfo != null) {
min = Math.min(min, leftInfo.min);
}
if (rightInfo != null) {
min = Math.min(min, rightInfo.min);
}
boolean isBST=true;
if(leftInfo!=null&& !leftInfo.isBST) {
isBST=false;
}
if(rightInfo!=null&&!rightInfo.isBST) {
isBST=false;
}
if(leftInfo!=null&&leftInfo.max>=x.value) {
isBST=false;
}
if(rightInfo!=null&& rightInfo.min<=x.value) {
isBST=false;
}
return new Info(isBST,max,min);
}
}
🍅二叉树最大直径
题目:
给定一棵二叉树的头节点head,任何两个节点之间都存在距离,返回整棵二叉树的最大距离
题解思路:
对于任一节点X,以X为头节点的二叉树的最大距离有以下三种可能:
1、X左树的最大距离(不经过X)
2、X右树的最大距离(不经过X)
3、X左树与X最远的距离+X右树与X最远的距离+1(左树或右树与X的最大距离就是树的高度)
所以信息体需要包含以下内容:
1、最大距离
2、树的高度
代码实现:
import java.util.ArrayList;
public class MaxDistance {
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int value) {
this.value = value;
}
}
public static class Info {
public int maxDistance;
public int height;
public Info(int maxDistance, int height) {
this.maxDistance = maxDistance;
this.height = height;
}
}
public static int maxDistance(Node head) {
return process(head).maxDistance;
}
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 p1=leftInfo.maxDistance;
int p2=rightInfo.maxDistance;
int p3= leftInfo.height+ rightInfo.height+1;
int maxDistance=Math.max(Math.max(p1,p2),p3);
return new Info(maxDistance,height);
}
}
🍅判断二叉树是不是满二叉树
题目:
给定一棵二叉树的头节点head,判断这棵二叉树是不是满二叉树
题解思路:
满二叉树的高度为h,则节点数为2^h-1.
所以定义的信息体包含两个信息(高度和节点数)
返回头节点的信息体就能判断该二叉树是不是满二叉树。
代码实现:
public class IsFull {
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int value) {
this.value = value;
}
}
public static class Info {
public int height;
public int nodes;
public Info(int height, int nodes) {
this.height = height;
this.nodes = nodes;
}
}
public static boolean isFull(Node head) {
if(head==null) {
return true;
}
Info all=process(head);
return (1<< all.height)-1== all.nodes;
}
public static Info process(Node head) {
if(head==null) {
return new Info(0,0);
}
Info leftInfo=process(head.left);
Info rightInfo=process(head.right);
int height=Math.max(leftInfo.height, rightInfo.height)+1;
int nodes= leftInfo.nodes+ rightInfo.nodes;
return new Info(height,nodes);
}
}
🍅最大二叉搜索树
题目:
给定一棵二叉树的头节点head,返回这颗二叉树中最大的二叉搜索子树的大小
题解思路:
求最大二叉搜索树,当X节点不做头时,有两种可能:
1、X左子树的最大二叉搜索树大小
2、X右子树的最大二叉搜索树大小
当X节点做头时,需要知道以下三个信息:
1、X左树是否是BST X右树是否是BST
2、X左树的max是否小于X.val X右树的min是否大于X.val
3、X左树的size +X右树的size+1
得到信息体即包含以下信息:
1、最大二叉搜索子树大小
2、树上max
3、树上min
4、整棵树的size
5、是否是BST(该条件可以省略,如果1 == 4即可得到5)
代码实现:
public class MaxSubBST {
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int value) {
this.value = value;
}
}
public static class Info {
public int maxSubBSTHead;
public int size;
public int max;
public int min;
public Info(int maxSubBSTHead, int size, int max, int min) {
this.maxSubBSTHead = maxSubBSTHead;
this.size = size;
this.max = max;
this.min = min;
}
}
public static Info process(Node x) {
if(x==null) {
return null;
}
Info leftInfo=process(x.left);
Info rightInfo=process(x.right);
int max=x.value;
int min=x.value;
int size=1;
if(leftInfo!=null) {
max=Math.max(max, leftInfo.max);
min=Math.min(min, leftInfo.min);
size+= leftInfo.size;
}
if(rightInfo!=null) {
max=Math.max(max, rightInfo.max);
min=Math.min(min, rightInfo.min);
size+= rightInfo.size;
}
int p1=-1;
if(leftInfo!=null) {
p1=leftInfo.maxSubBSTHead;
}
int p2=-1;
if(rightInfo!=null) {
p2=rightInfo.maxSubBSTHead;
}
int p3=-1;
boolean leftBST=leftInfo==null?true:(leftInfo.maxSubBSTHead== leftInfo.size);
boolean rightBST=rightInfo==null?true:(rightInfo.maxSubBSTHead== rightInfo.size);
if(leftBST&&rightBST) {
boolean leftMaxLessX=leftInfo==null?true:(leftInfo.max<x.value);
boolean rightMinMoreX=rightInfo==null?true:(x.value< rightInfo.min);
if(leftMaxLessX&&rightMinMoreX) {
p3=size;
}
}
return new Info(Math.max(p1,Math.max(p2,p3)),size,max,min);
}
}
🍅完全二叉树判断套路版
题目:
判断二叉树是不是完全二叉树(一般方法解决、递归套路解决)
题解思路:
对于以节点X为头节点的二叉树,有以下四种可能,可以使得该二叉树为完全二叉树。
1)左树满,右树满,左树高度 == 右树高度
2)左树是完全二叉树,右树满,左树高度 == 右树高度+1
3)左树满,右树满,左高 == 右高+1
4)左树满。右树是完全二叉树,左高 == 右高
所以定义信息体,需要包含以下信息:
1、是否满
2、是否是完全二叉树
3、高度
代码实现:
public class IsCBT {
public static class TreeNode {
public int val;
public TreeNode left;
public TreeNode right;
public TreeNode(int val) {
this.val = val;
}
}
public static class Info {
public boolean isFull;
public boolean isCBT;
public int height;
public Info(boolean isFull, boolean isCBT, int height) {
this.isFull = isFull;
this.isCBT = isCBT;
this.height = height;
}
}
public static Info process(TreeNode x) {
if(x==null) {
return new Info(true,true,0);
}
Info leftInfo=process(x.left);
Info rightInfo=process(x.right);
int height=Math.max(leftInfo.height,rightInfo.height)+1;
boolean isFull= leftInfo.isFull&& rightInfo.isFull&&leftInfo.height== rightInfo.height;
boolean isCBT=false;
if(leftInfo.isFull&& rightInfo.isFull&&leftInfo.height== rightInfo.height) {
isCBT=true;
}else if(leftInfo.isCBT&& rightInfo.isFull&&leftInfo.height== rightInfo.height+1) {
isCBT=true;
}else if (leftInfo.isFull&& rightInfo.isFull&&leftInfo.height== rightInfo.height+1) {
isCBT=true;
}else if(leftInfo.isFull&&rightInfo.isCBT&&leftInfo.height== rightInfo.height) {
isCBT=true;
}
return new Info(isFull,isCBT,height);
}
}
🍅最大二叉搜索树的头节点
给定一棵二叉树的头节点head,返回这颗二叉树中最大的二叉搜索子树的头节点
题解思路:
求最大二叉搜索树的头节点,对于任一节点X来说,有以下两种情况。
1、与X无关(即X不是最大二叉搜索树的头节点)
1)X左树的最大二叉搜索树的头节点
2)X右树的最大二叉搜索树的头节点
2、与X有关(即X为最大二叉搜索树的头节点),那么需要以下条件
1)左树、右树为二叉搜索树
2)左树最大值<X.val 右树最小值>X.val
3)该树的大小
所以信息体需包含以下信息:
1)最大二叉搜索树的头节点
2)最大二叉搜索树的节点个数
3)max
4)min
代码实现:
public class MaxSubBSTHead {
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int value) {
this.value = value;
}
}
public static class Info {
public Node maxSubBSTHead;
public int maxSubBSTSize;
public int max;
public int min;
public Info(Node maxSubBSTHead, int maxSubBSTSize, int max, int min) {
this.maxSubBSTHead = maxSubBSTHead;
this.maxSubBSTSize = maxSubBSTSize;
this.max = max;
this.min = min;
}
}
public static Info process(Node x) {
if(x==null) return null;
Info leftInfo=process(x.left);
Info rightInfo=process(x.right);
int max=x.value;
int min=x.value;
Node maxSubBSTHead=null;
int maxSubBSTSize=0;
if(leftInfo!=null) {
max=Math.max(max, leftInfo.max);
min=Math.min(min, leftInfo.min);
maxSubBSTHead=leftInfo.maxSubBSTHead;
maxSubBSTSize= leftInfo.maxSubBSTSize;
}
if(rightInfo!=null) {
max=Math.max(max, rightInfo.max);
min=Math.min(min, rightInfo.min);
if(rightInfo.maxSubBSTSize>maxSubBSTSize) {
maxSubBSTHead=rightInfo.maxSubBSTHead;
maxSubBSTSize= rightInfo.maxSubBSTSize;
}
}
if((leftInfo==null?true:(leftInfo.maxSubBSTHead ==x.left&&leftInfo.max<x.value))&&
(rightInfo==null?true:(rightInfo.maxSubBSTHead==x.right&&rightInfo.min>x.value))) {
maxSubBSTHead=x;
maxSubBSTSize=(leftInfo==null?0: leftInfo.maxSubBSTSize)+(rightInfo==null?0: rightInfo.maxSubBSTSize)+1;
}
return new Info(maxSubBSTHead,maxSubBSTSize,max,min);
}
}
🍅最低公共祖先
题目:
给定一棵二叉树的头节点head,和另外两个节点a和b,返回a和b的最低公共祖先
题解思路:
对于任一节点X,就找X是否是a、b最低公共祖先即可。
1)与X无关(X不是最低汇聚点)
1.左树有答案
2.右树有答案
3.a、b不都在X为头节点的子树上
2)X是答案
1.左右子树a、b各一个
2.X是a,b在左子树或者右子树
3.X是b,a在左子树或者右子树
信息体包含:
1.a是否在树上
2.b是否在树上
3.最低公共祖先节点
代码实现:
public class LowestAncestor {
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int value) {
this.value = value;
}
}
public static Node lowestAncestor(Node head,Node a,Node b) {
return process(head,a,b).ans;
}
public static class Info {
public boolean findA;
public boolean findB;
public Node ans;
public Info(boolean findA, boolean findB, Node ans) {
this.findA = findA;
this.findB = findB;
this.ans = ans;
}
}
public static Info process(Node x,Node a,Node b) {
if(x==null) {
return new Info(false,false,null);
}
Info leftInfo=process(x.left,a,b);
Info rightInfo=process(x.right,a,b);
boolean findA=(x==a)|| leftInfo.findA|| rightInfo.findA;
boolean findB=(x==b)|| leftInfo.findB|| rightInfo.findB;
Node ans=null;
if(leftInfo.ans!=null) {
ans=leftInfo.ans;
}else if(rightInfo.ans!=null) {
ans=rightInfo.ans;
}else {
if(findA&&findB) {
ans=x;
}
}
return new Info(findA,findB,ans);
}
}
🍅派对的最大快乐值
题目:
员工信息的定义如下:
class Employee {
public int happy; // 这名员工可以带来的快乐值
List subordinates; // 这名员工有哪些直接下级
}
公司的每个员工都符合 Employee 类的描述。整个公司的人员结构可以看作是一棵标准的、 没有环的多叉树
树的头节点是公司唯一的老板,除老板之外的每个员工都有唯一的直接上级
叶节点是没有任何下属的基层员工(subordinates列表为空),除基层员工外每个员工都有一个或多个直接下级
这个公司现在要办party,你可以决定哪些员工来,哪些员工不来,规则:
1.如果某个员工来了,那么这个员工的所有直接下级都不能来
2.派对的整体快乐值是所有到场员工快乐值的累加
3.你的目标是让派对的整体快乐值尽量大
给定一棵多叉树的头节点boss,请返回派对的最大快乐值。
题解思路:
对于任一节点X,若想求最大快乐值,有以下两种情况:
1、X来,则X.happy+所有直系子节点不来的maxHappy
2、X不来,则0+所有直系字节的来与不来两种情况下获得的maxHappy
则得到信息体包含以下信息:
X来的情况下的maxHappy
X不来的情况下的maxHappy
代码实现:
public class MaxHappy {
public static class Employee {
public int happy;
public List<Employee> nexts;
public Employee(int happy) {
this.happy = happy;
this.nexts = new ArrayList<>();
}
}
public static int maxHappy(Employee boss) {
Info allInfo=process(boss);
return Math.max(allInfo.no, allInfo.yes);
}
public static class Info {
public int no;
public int yes;
public Info(int no, int yes) {
this.no = no;
this.yes = yes;
}
}
public static Info process(Employee x) {
if(x==null) {
return new Info(0,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);
}
}
⭐️最后的话⭐️
总结不易,希望uu们不要吝啬你们的👍哟(^U^)ノ~YO!!如有问题,欢迎评论区批评指正😁