leetcode
leetcode 301 ~ 350
最大二叉搜索子树

最大二叉搜索子树

难度:

标签:

题目描述

代码结果

运行时间: 26 ms, 内存: 18.1 MB


/*
 * 思路:
 * 1. 使用递归方法,通过流的方式计算每个节点为根的子树的大小。
 * 2. 对于每个节点,判断其左子树和右子树是否为二叉搜索树(BST)。
 * 3. 记录最大BST的大小。
 */
 
import java.util.stream.Stream;
 
class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
}
 
public class Solution {
    class ResultType {
        boolean isBST;
        int size;
        int minVal, maxVal;
        ResultType(boolean isBST, int size, int minVal, int maxVal) {
            this.isBST = isBST;
            this.size = size;
            this.minVal = minVal;
            this.maxVal = maxVal;
        }
    }
 
    private int maxBSTSize = 0;
 
    public int largestBSTSubtree(TreeNode root) {
        helper(root);
        return maxBSTSize;
    }
 
    private ResultType helper(TreeNode node) {
        if (node == null) {
            return new ResultType(true, 0, Integer.MAX_VALUE, Integer.MIN_VALUE);
        }
 
        ResultType left = helper(node.left);
        ResultType right = helper(node.right);
 
        if (Stream.of(left.isBST, right.isBST).allMatch(b -> b) && node.val > left.maxVal && node.val < right.minVal) {
            int size = left.size + right.size + 1;
            maxBSTSize = Math.max(maxBSTSize, size);
            return new ResultType(true, size, Math.min(left.minVal, node.val), Math.max(right.maxVal, node.val));
        } else {
            return new ResultType(false, 0, 0, 0);
        }
    }
}
 

解释

方法:

该题解使用深度优先遍历(DFS)的方法来遍历二叉树的每个节点。对于每个节点,判断其是否能成为一个二叉搜索树(BST)的根节点。如果当前节点能成为BST的根,那么以该节点为根的子树就是一个BST,记录其节点数,并与当前最大BST节点数比较,更新最大值。DFS函数返回一个元组,包含当前子树是否为BST、子树的最小值、最大值和节点数。通过比较当前节点与其左右子树的最大最小值,可以判断当前节点是否能成为BST的根。

时间复杂度:

O(n)

空间复杂度:

O(h),最坏情况下O(n),平均情况下O(logn)

代码细节讲解

🦆
在DFS的返回值中,元组的各个部分分别代表什么?具体如何使用这些信息来判断一个节点是否能成为BST的根节点?
在DFS的返回值中,元组包含四个部分:(is_bst, min_val, max_val, cur_num)。其中,is_bst是一个布尔值,表示当前子树是否为二叉搜索树;min_val是当前子树中的最小值;max_val是当前子树中的最大值;cur_num是当前子树的节点数。使用这些信息来判断一个节点是否能成为BST的根节点时:首先检查左右子树是否分别是BST(即左右子树的is_bst都为True),然后确保当前节点的值大于左子树的最大值且小于右子树的最小值。如果这些条件都满足,当前节点可以成为BST的根节点。
🦆
题解中提到,如果左右子树都是BST且满足一定条件,当前节点也可以是BST的根。这里的条件是什么?为什么需要这些条件?
题解中提到的条件是:左子树的所有节点值都必须小于当前节点的值,右子树的所有节点值都必须大于当前节点的值。这些条件是必须的,因为二叉搜索树的定义要求任一节点的左子树只包含小于当前节点的值的节点,右子树只包含大于当前节点的值的节点。只有当这些条件被满足时,整个树结构才能维持BST的性质。
🦆
在处理只有左子树或只有右子树的情况时,题解如何确保当前节点的值与其子树的值满足BST的性质?
在只有左子树的情况下,题解确保当前节点的值大于左子树的最大值,这符合BST的性质,即所有左侧节点的值必须小于根节点的值。在只有右子树的情况下,确保当前节点的值小于右子树的最小值,这同样符合BST的性质,即所有右侧节点的值必须大于根节点的值。通过这种方式,题解确保了即使只有一侧子树存在时,当前节点与其子树的值也能满足BST的基本要求。
🦆
题解中没有明确提到如何处理当前节点的左子树或右子树不是BST的情况。这种情况应该如何处理?
如果当前节点的左子树或右子树不是BST(即is_bst为False),则当前节点本身也不能成为BST的根节点。在这种情况下,我们不会尝试将当前节点作为BST的根,而是直接返回False以及无效的最小值和最大值。这样做是因为,如果任何子树不满足BST的性质,那么整个包含该子树的更大的树也不能是BST。

相关问题