方法1 O(N^2)
自顶向下,先检查当前的树是不是bst,如果是bst,求子树节点数量。
- 然后向下递归
class Solution {
// 返回root为节点的树中的最大bst节点数量
public int largestBSTSubtree(TreeNode root) {
if (root == null) {
return 0;
}
if (isBST(root, Integer.MIN_VALUE, Integer.MAX_VALUE)) {
return getNumberOfNodes(root);
}
return Math.max(largestBSTSubtree(root.left), largestBSTSubtree(root.right));
}
// 检查一棵树是否是bst
public boolean isBST(TreeNode root, int min, int max) {
if (root == null) {
return true;
}
if (root.val >= max || root.val <= min) {
return false;
}
return isBST(root.left, min, root.val) && isBST(root.right, root.val, max);
}
// 获取节点数量
public int getNumberOfNodes(TreeNode root) {
if (root == null) {
return 0;
}
return 1 + getNumberOfNodes(root.left) + getNumberOfNodes(root.right);
}
}
方法2 O(N) bottm-up
新增节点信息,包含了:
- 当前节点的子树中的最小值
- 当前节点的子树中的最大值
- 子树中出现过的bst的最大size
然后向上返回
class Solution {
// 新建节点信息
class NodeInfo {
int subTreeMin; // 当前节点的子树中的最小值
int subTreeMax; // 当前节点的子树中的最大值
int maxBSTSize; // 子树中出现过的bst的最大size
NodeInfo(int min, int max, int size) {
this.subTreeMin = min;
this.subTreeMax = max;
this.maxBSTSize = size;
}
}
// dfs返回当前节点的 nodeinfo
public NodeInfo dfs(TreeNode root) {
if (root == null) {
// 这样设置方便叶子结点计算info,叶子结点也是bst
return new NodeInfo(Integer.MAX_VALUE, Integer.MIN_VALUE, 0);
}
NodeInfo leftInfo = dfs(root.left);
NodeInfo rightInfo = dfs(root.right);
// 满足这个条件,说明当前节点构成了bst,更新信息
if (root.val < rightInfo.subTreeMin && root.val > leftInfo.subTreeMax) {
// Math.min的目的是,如果当前节点是叶子结点,之前的min是无穷大,max同理
return new NodeInfo(Math.min(root.val, leftInfo.subTreeMin),
Math.max(root.val, rightInfo.subTreeMax),
1 + leftInfo.maxBSTSize + rightInfo.maxBSTSize);
}
// 当前节点不构成bst,那么他的所有父节点,不可能构成包含当前节点在内的bst
// 所以这么设置不让上层节点走到26行代码,但是同时也要返回下层存在的bst大小信息
return new NodeInfo(Integer.MIN_VALUE, Integer.MAX_VALUE,
Math.max(leftInfo.maxBSTSize, rightInfo.maxBSTSize));
}
// 返回根节点信息中的maxbstsize即可
public int largestBSTSubtree(TreeNode root) {
return dfs(root).maxBSTSize;
}
}