方法步骤
- 假设以X节点为头,假设可以向X左树和X右树要任何信息
- 在上一步的假设下,讨论以X为头节点的树,得到答案的可能性(最重要)
- 列出所有可能性后,确定到底需要向左树和右树要什么样的信息
- 把左树信息和右树信息求全集,就是任何一棵子树都需要返回的信息S
- 递归函数都返回S,每一棵子树都这么要求
- 写代码,在代码中考虑如何把左树的信息和右树信息整合出整棵树的信息
判断二叉树是否是搜索二叉树
public static boolean isBST2(Node head) {
if (head == null) {
return true;
}
return process(head).isBST;
}
// 判断当前树是否为搜索二叉树需要哪些信息?
// 1. 左右树是否都是bst
// 2. 左树最大值,是否小于头结点的值,右树最小值,是否大于头结点的值
public static class Info {
public boolean isBST;
public int max;
public int min;
public Info(boolean i, int ma, int mi) {
isBST = i;
max = ma;
min = mi;
}
}
public static Info process(Node x) {
if (x == null) {
return null; // Info不确定,返回空
}
Info leftInfo = process(x.left);
Info rightInfo = process(x.right);
Boolean isBST = true;
int max = x.value,min = x.value;
if(x.left != null) { // 可能返回空的leftInfo,所以要判断
max = Math.max(max,leftInfo.max);
min = Math.min(min,leftInfo.min);
if(!leftInfo.isBST || leftInfo.max >= x.value) {
isBST = false;
}
}
if(x.right != null) {
max = Math.max(max,rightInfo.max);
min = Math.min(min,rightInfo.min);
if(!rightInfo.isBST || rightInfo.min <= x.value) {
isBST = false;
}
}
return new Info(isBST,max,min);
}
判断二叉树是不是平衡二叉树
public static boolean isBalanced2(Node head) {
return process(head).isBalanced;
}
// 判断当前树是否为平衡二叉树需要哪些信息?
// 1. 左右树是否都是平衡二叉树
// 2. 左树和又树高度是否相差小于等于 1
public static class Info{
public boolean isBalanced;
public int height;
public Info(boolean i, int h) {
isBalanced = i;
height = h;
}
}
public static Info process(Node x) {
if(x == null) {
return new Info(true, 0); // 空树是平衡二叉树,高度为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) {
isBalanced = false;
}
if(!rightInfo.isBalanced) {
isBalanced = false;
}
if(Math.abs(leftInfo.height - rightInfo.height) > 1) {
isBalanced = false;
}
return new Info(isBalanced, height);
}
判断二叉树是不是满二叉树
// 第一种方法
// 收集整棵树的高度h,和节点数n
// 只有满二叉树满足 : 2 ^ h - 1 == n
public static boolean isFull1(Node head) {
if (head == null) {
return true;
}
Info1 all = process1(head);
return (1 << all.height) - 1 == all.nodes;
}
public static class Info1 {
public int height;
public int nodes;
public Info1(int h, int n) {
height = h;
nodes = n;
}
}
public static Info1 process1(Node head) {
if (head == null) {
return new Info1(0, 0);
}
Info1 leftInfo = process1(head.left);
Info1 rightInfo = process1(head.right);
int height = Math.max(leftInfo.height, rightInfo.height) + 1;
int nodes = leftInfo.nodes + rightInfo.nodes + 1;
return new Info1(height, nodes);
}
// 第二种方法
// 收集子树是否是满二叉树
// 收集子树的高度
// 左树满 && 右树满 && 左右树高度一样 -> 整棵树是满的
public static boolean isFull2(Node head) {
if (head == null) {
return true;
}
return process2(head).isFull;
}
public static class Info2 {
public boolean isFull;
public int height;
public Info2(boolean f, int h) {
isFull = f;
height = h;
}
}
public static Info2 process2(Node h) {
if (h == null) {
return new Info2(true, 0);
}
Info2 leftInfo = process2(h.left);
Info2 rightInfo = process2(h.right);
boolean isFull = leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height;
int height = Math.max(leftInfo.height, rightInfo.height) + 1;
return new Info2(isFull, height);
}
最大二叉搜索子树
public static int maxSubBSTSize2(Node head) {
if(head == null) {
return 0;
}
return process(head).maxBSTSubtreeSize;
}
// 1. 不考虑x,需要左右树的 maxBSTSubtreeSize
// 2. 考虑x,需要知道,带上x节点,整个树是不是bst,以及整个树的节点数
// 于是就需要,min,max,左右树是不是bst(可以省略化简掉),左右树的节点数
public static class Info {
public int maxBSTSubtreeSize;
public int allSize;
public int max;
public int min;
public Info(int m, int a, int ma, int mi) {
maxBSTSubtreeSize = m;
allSize = a;
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 max = x.value;
int min = x.value;
int allSize = 1;
int p1 = -1,p2 = -1,p3 = -1;
if(x.left != null) {
max = Math.max(max,leftInfo.max);
min = Math.min(min,leftInfo.min);
allSize += leftInfo.allSize;
p1 = leftInfo.maxBSTSubtreeSize;
}
if(x.right != null) {
max = Math.max(max,rightInfo.max);
min = Math.min(min,rightInfo.min);
allSize += rightInfo.allSize;
p2 = rightInfo.maxBSTSubtreeSize;
}
// 这里都是在判断,加上x是否为bst
boolean isLeftBST = leftInfo == null ? true : (leftInfo.maxBSTSubtreeSize == leftInfo.allSize);
boolean isRightBST = rightInfo == null ? true : (rightInfo.maxBSTSubtreeSize == rightInfo.allSize);
if(isLeftBST && isRightBST) {
boolean condition1 = leftInfo == null ? true : leftInfo.max < x.value;
boolean condition2 = rightInfo == null ? true : rightInfo.min > x.value;
if(condition1 && condition2) {
p3 = allSize;
}
}
return new Info(Math.max(p1,Math.max(p2,p3)),allSize,max,min);
}
二叉树的最大距离
给定一棵二叉树的头节点head,任何两个节点之间都存在距离,返回整棵二叉树的最大距离
public static int maxDistance2(Node head) {
return process(head).maxDistance;
}
// 1. 不考虑x,左右树的最大距离求最大
// 2. 考虑x,需要知道左右树高度,二者较大加 1,就是通过x的最大距离
public static class Info {
public int maxDistance;
public int height;
public Info(int m, int h) {
maxDistance = m;
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);
}
最低公共祖先
给定一棵二叉树的头节点head,和另外两个节点a和b。返回a和b的最低公共祖先
public static Node lowestAncestor2(Node head, Node a, Node b) {
return process(head, a, b).ans;
}
// 1. x不是答案,可能答案在左,也可能在右
// 2. x是答案,可能左树有a,右树有b,也可能x是a或b,左右树有a或b
public static class Info {
public boolean findA;
public boolean findB;
public Node ans;
public Info(boolean fA, boolean fB, Node an) {
findA = fA;
findB = fB;
ans = an;
}
}
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);
Node ans = null;
boolean findA = (x == a) || leftInfo.findA || rightInfo.findA;
boolean findB = (x == b) || leftInfo.findB || rightInfo.findB;
if(leftInfo.ans != null) {
ans = leftInfo.ans;
} else if(rightInfo.ans != null) {
ans = rightInfo.ans;
} else if(findA && findB) { //这里else不能不写,因为如果左右树有答案,就和x无关
ans = x;
}
return new Info(findA,findB,ans);
}
判断是否是完全二叉树
public static boolean isCBT2(Node head) {
return process(head).isCBT;
}
// 如果是完全二叉树,右哪些可能性呢?
// 1. 左满右满 右比左高1 或 相等
// 2. 左完全右满 右比左高1
// 3. 左满右完全 左右高相等
public static class Info {
public boolean isFull;
public boolean isCBT;
public int height;
public Info(boolean full, boolean cbt, int h) {
isFull = full;
isCBT = cbt;
height = h;
}
}
public static Info process(Node 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) {
if(leftInfo.height == rightInfo.height + 1 || leftInfo.height == rightInfo.height) {
isCBT = true;
}
}
if(leftInfo.isCBT && rightInfo.isFull && leftInfo.height == rightInfo.height + 1) {
isCBT = true;
}
if(leftInfo.isFull && rightInfo.isCBT && leftInfo.height == rightInfo.height) {
isCBT = true;
}
return new Info(isFull,isCBT,height);
}
派对的最大快乐值
公司的每个员工都符合 Employee 类的描述。整个公司的人员结构可以看作是一棵标准的、 没有环的多叉树。树的头节点是公司唯一的老板。除老板之外的每个员工都有唯一的直接上级。 叶节点是没有任何下属的基层员工(subordinates列表为空),除基层员工外,每个员工都有一个或多个直接下级。 这个公司现在要办party,你可以决定哪些员工来,哪些员工不来,规则:
- 如果某个员工来了,那么这个员工的所有直接下级都不能来
- 派对的整体快乐值是所有到场员工快乐值的累加
- 你的目标是让派对的整体快乐值尽量大 给定一棵多叉树的头节点boss,请返回派对的最大快乐值。
public static int maxHappy2(Employee head) {
Info allInfo = process(head);
return Math.max(allInfo.no, allInfo.yes);
}
// 1. 当前员工来时,最大快乐值,是当前快乐值,加上下下属来时最大快乐值总和
// 2. 当前员工不来时,最大快乐值,是直接下属来时最大快乐值 和 不来时最大快乐值 取较大者的总和
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 == 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);
}