【思路详解+详细注释】小白都能看懂的力扣算法详解——树

一 LC95.不同的二叉搜索树II

题目要求:

给你一个整数 n ,请你生成并返回所有由 n 个节点组成且节点值从 1 到 n 互不相同的不同 二叉搜索树 。可以按 任意顺序 返回答案。

95. 不同的二叉搜索树 II - 力扣(LeetCode)

思路分析:

        要生成所有由 n 个节点组成的、且节点值从 1n 互不相同的不同二叉搜索树 (BST),可以使用递归和动态规划相结合的方式。对于每个数字 i(从 1n),我们可以将 i 作为根节点,递归生成以 1i-1 为节点的左子树集合,以及以 i+1n 为节点的右子树集合,然后将这些左子树和右子树进行组合,形成以 i 为根节点的所有可能的二叉搜索树。当 start > end 时,返回一个 null 节点表示没有子树(空树)。

        对于每个根节点 i,从左子树集合和右子树集合中取出一个左子树和一个右子树,组合成一棵新树,并将其加入结果集中。

完整代码示例:

import java.util.ArrayList;
import java.util.List;

// 定义二叉树节点类
class TreeNode {
    int val;  // 节点值
    TreeNode left;  // 左子树
    TreeNode right;  // 右子树
    
    // 构造函数,初始化节点值
    TreeNode(int x) { 
        val = x; 
    }
}

public class Solution {
    // 生成所有由 n 个节点组成的不同二叉搜索树
    public List<TreeNode> generateTrees(int n) {
        // 如果 n 为 0,则返回一个空的列表
        if (n == 0) {
            return new ArrayList<>();
        }
        // 调用递归方法生成从 1 到 n 的所有二叉搜索树
        return generateTrees(1, n);
    }

    // 递归方法:生成从 start 到 end 范围内所有可能的二叉搜索树
    private List<TreeNode> generateTrees(int start, int end) {
        List<TreeNode> allTrees = new ArrayList<>();  // 存储所有可能的树

        // 递归的基准情况:如果 start > end,则返回包含 null 的列表,表示没有子树
        if (start > end) {
            allTrees.add(null);
            return allTrees;
        }

        // 遍历范围内的每个数字 i,将其作为当前树的根节点
        for (int i = start; i <= end; i++) {
            // 递归生成所有可能的左子树,左子树的节点范围是 start 到 i-1
            List<TreeNode> leftTrees = generateTrees(start, i - 1);

            // 递归生成所有可能的右子树,右子树的节点范围是 i+1 到 end
            List<TreeNode> rightTrees = generateTrees(i + 1, end);

            // 将每个左子树和右子树组合到当前根节点 i
            for (TreeNode left : leftTrees) {
                for (TreeNode right : rightTrees) {
                    // 创建一个新的树节点,将 i 作为根节点
                    TreeNode currentTree = new TreeNode(i);
                    currentTree.left = left;  // 连接左子树
                    currentTree.right = right;  // 连接右子树
                    allTrees.add(currentTree);  // 将生成的树加入结果列表
                }
            }
        }

        // 返回当前范围内所有可能的二叉搜索树
        return allTrees;
    }
}

二 LC96.不同的二叉搜索树

题目要求:

给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。

96. 不同的二叉搜索树 - 力扣(LeetCode)

思路分析:

       这是一个典型的动态规划问题,可以使用卡特兰数(Catalan Number)来求解。设 G(n) 表示有 n 个节点的二叉搜索树的总数,对于每个 i1 <= i <= n),我们可以将 i 作为根节点。左子树的节点个数为 i-1,即 G(i-1)。右子树的节点个数为 n-i,即 G(n-i)。因此,可以得到状态转移方程: G(n)=∑i=1nG(i−1)×G(n−i)G(n) = \sum_{i=1}^{n} G(i-1) \times G(n-i)G(n)=i=1∑n​G(i−1)×G(n−i)。这里我们需要去判断一些特殊情况,也就是当没有节点时,只有一种(空树)的情况(G(0) = 1)或者当只有一个节点时的情况(G(1) = 1)。

完整代码示例:

public class Solution {
    // 计算由 n 个节点组成的不同二叉搜索树的数量
    public int numTrees(int n) {
        // 动态规划数组,用于存储不同节点数的BST数量
        int[] dp = new int[n + 1];
        
        // 基础条件
        dp[0] = 1; // 空树的情况
        dp[1] = 1; // 只有一个节点的情况

        // 从2开始计算,直到n
        for (int i = 2; i <= n; i++) {
            // 对于每个i,计算不同根节点的所有情况
            for (int j = 1; j <= i; j++) {
                // dp[i] += 左子树的BST数量 * 右子树的BST数量
                dp[i] += dp[j - 1] * dp[i - j];
            }
        }
        
        // 返回结果,即由n个节点组成的BST的数量
        return dp[n];
    }
}

三 LC98.验证二叉搜索树

题目要求:

给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

有效 二叉搜索树定义如下:

  • 节点的左子树只包含 小于 当前节点的数。
  • 节点的右子树只包含 大于 当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树。

98. 验证二叉搜索树 - 力扣(LeetCode)

思路分析:

       要判断一个二叉树是否是有效的二叉搜索树,我们可以使用中序遍历的思想。对于二叉搜索树,按中序遍历顺序得到的节点值序列应该是严格递增的。因此,通过中序遍历来检查节点值是否递增,可以判断该二叉树是否是有效的二叉搜索树。

        使用递归来遍历每个节点,同时传递当前节点的上下界(最小值和最大值),确保当前节点的值在这些上下界之间。对于每个节点而言,如果当前节点的值不在给定的上下界之间,则该树不是二叉搜索树。然后递归检查左子树和右子树,对左子树递归时,更新上界为当前节点值,对右子树递归时,更新下界为当前节点值。

完整代码示例:

class TreeNode {
    int val;  // 节点值
    TreeNode left;  // 左子树
    TreeNode right;  // 右子树
    
    // 构造函数,初始化节点值
    TreeNode(int x) { 
        val = x; 
    }
}

public class Solution {
    // 判断给定的二叉树是否是一个有效的二叉搜索树
    public boolean isValidBST(TreeNode root) {
        // 调用递归方法,初始上下界设为Long的最小值和最大值
        return isValidBST(root, Long.MIN_VALUE, Long.MAX_VALUE);
    }

    // 递归方法,判断以当前节点为根的子树是否满足BST条件
    private boolean isValidBST(TreeNode node, long min, long max) {
        // 空节点直接返回true
        if (node == null) {
            return true;
        }
        
        // 如果当前节点值不在合法范围内,则返回false
        if (node.val <= min || node.val >= max) {
            return false;
        }

        // 递归检查左子树,更新上界为当前节点值
        // 递归检查右子树,更新下界为当前节点值
        return isValidBST(node.left, min, node.val) && isValidBST(node.right, node.val, max);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值