二叉树中最大的二叉搜索子树的大小
给定一棵二叉树的头节点head,
返回这颗二叉树中最大的二叉搜索子树的头节点
分析可能性:
-
与X头无关:
- X左树最大可能性
- X右树最大可能性
-
与X头有关:
- 以X为头,整体全是BST搜索二叉树,X左为BST和X右为BST
- X左树的最大值和X右树的最小值
- X左树的最大Size和X右树的最大Size
判断二叉树是不是搜索二叉树原则:
- X左树是BST (BST搜索二叉树)
- X右树是BST
- X左树最大伯max < X
- X右树景小值min > X
如果整棵树最大BST大小跟Size相等,是BST则与X头有关的第3点可以不用,这种情况就是只有X头的情况或者他的左右子树都一样。
使用递归方法:
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
public static int getBSTSize(Node head) {
if (head == null) {
return 0;
}
ArrayList<Node> arr = new ArrayList<>();
in(head, arr);
for (int i = 1; i < arr.size(); i++) {
if (arr.get(i).value <= arr.get(i - 1).value) {
return 0;
}
}
return arr.size();
}
public static void in(Node head, ArrayList<Node> arr) {
if (head == null) {
return;
}
in(head.left, arr);
arr.add(head);
in(head.right, arr);
}
public static int maxSubBSTSize1(Node head) {
if (head == null) {
return 0;
}
int h = getBSTSize(head);
if (h != 0) {
return h;
}
return Math.max(maxSubBSTSize1(head.left), maxSubBSTSize1(head.right));
}
改成dp方法:
// 二叉树中最大的二叉搜索子树的大小
public static int maxSubBSTSize2(Node head) {
if(head == null) {
return 0;
}
return process(head).maxBSTSubtreeSize;
}
// 要求左右子树返回一样的信息:
// 1. 最大BST的size
// 2. 是不是BST
// 3. 整棵树最大值
// 4. 整棵树最小值
// X不做为头:
// 1. X左maxBSTSubtreeSize
// 2. X右maxBSTSubtreeSize
// X为头
// 1. X左BST X右BST
// 2. X左max X右min
// 3. X左size X右size
// 可以信息压缩,如果整棵树最大BST大小跟size相等--->是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;
if (leftInfo != null) {
max = Math.max(leftInfo.max, max);
min = Math.min(leftInfo.min, min);
allSize += leftInfo.allSize;
}
if (rightInfo != null) {
max = Math.max(rightInfo.max, max);
min = Math.min(rightInfo.min, min);
allSize += rightInfo.allSize;
}
int p1 = -1;
if (leftInfo != null) {
p1 = leftInfo.maxBSTSubtreeSize;
}
int p2 = -1;
if (rightInfo != null) {
p2 = rightInfo.maxBSTSubtreeSize;
}
int p3 = -1;
// 左边为空就相当于你是搜索二叉树,如果最大搜索二叉树的大小等于你整棵树的大小 --- 右边也一样
boolean leftBST = leftInfo == null ? true : (leftInfo.maxBSTSubtreeSize == leftInfo.allSize);
boolean rightBST = rightInfo == null ? true : (rightInfo.maxBSTSubtreeSize == rightInfo.allSize);
if (leftBST && rightBST) {
// 如果你左边或右边为空树相当于就是搜索二叉树,否则就比较一下,实际节点你左边节点没数,这样也不破坏
boolean leftMaxLessX = leftInfo == null ? true : (leftInfo.max < x.value);
boolean rightMinMoreX = rightInfo == null ? true : (x.value < rightInfo.min);
if (leftMaxLessX && rightMinMoreX) {
// 左树的allSize+右树的allSize
int leftSize = leftInfo == null ? 0 : leftInfo.allSize;
int rightSize = rightInfo == null ? 0 : rightInfo.allSize;
p3 = leftSize + rightSize + 1;
}
}
return new Info(Math.max(p1, Math.max(p2, p3)), allSize, max, min);
}