小M的好二叉树豆包|MarsCodeAI刷题

45 阅读3分钟

解题思路

  1. 理解题目:题目要求我们计算给定 n 个节点时可以构成的好二叉树的数量。好二叉树的定义是每个节点要么没有孩子,要么有两个孩子。这意味着树的节点数 n 必须是奇数。

  2. 动态规划:我们可以使用动态规划来解决这个问题。定义 dp[i] 为有 i 个节点时可以构成的好二叉树的数量。

  3. 状态转移方程:对于每个节点数 i,我们可以将其分解为根节点和左右子树。假设左子树有 j 个节点,那么右子树就有 i - 1 - j 个节点(因为根节点占用一个节点)。因此,状态转移方程为:

    plaintext

    dp[i] = sum(dp[j] * dp

    [i - 1 - j]) for j in 

    range(1, i, 2)

    这里 j 和 i - 1 - j 都是奇数,因为它们必须是好二叉树的节点数。

  4. 初始条件dp[1] = 1,因为只有一个节点时,只有一种好二叉树(即只有一个根节点)。

      1. 取模:由于结果需要对 10^9 + 7 取模,我们在每次计算时都需要取模。
public class Main {
    public static int solution(int n) {
        // 如果n是偶数,直接返回0,因为不可能构成好二叉树
        if (n % 2 == 0) return 0;

        // 定义模数
        final int MOD = 1000000007;

        // 初始化dp数组
        int[] dp = new int[n + 1];
        dp[1] = 1; // 初始条件

        // 填充dp数组
        for (int i = 3; i <= n; i += 2) {
            for (int j = 1; j < i; j += 2) {
                dp[i] = (dp[i] + (dp[j] * dp[i - 1 - j]) % MOD) % MOD;
            }
        }

        return dp[n];
    }

    public static void main(String[] args) {
        System.out.println(solution(5) == 2);
        System.out.println(solution(7) == 5);
        System.out.println(solution(9) == 14);
    }
}

代码解释

  1. 初始检查

    java

    if (n % 2 == 0) 

    return 0;

    这一行代码检查 n 是否为偶数。如果是偶数,直接返回 0,因为根据题目描述,好二叉树的节点数必须是奇数。

  2. 定义模数

    java

    final int MOD = 

    1000000007;

    这一行定义了一个常量 MOD,用于在计算过程中对结果取模,以防止整数溢出。

  3. 初始化 dp 数组

    java

    int[] dp = new int[n 

    + 1];

    dp[1] = 1; // 初始条件

    这里初始化了一个大小为 n + 1 的数组 dp,用于存储动态规划的结果。dp[1] 被初始化为 1,因为只有一个节点时,只有一种好二叉树(即只有一个根节点)。

  4. 填充 dp 数组

    java

    for (int i = 3; i <= 

    n; i += 2) {

        for (int j = 1; j 

        < i; j += 2) {

            dp[i] = (dp

            [i] + (dp[j] 

            * dp[i - 1 - 

            j]) % MOD) % 

            MOD;

        }

    }

    这一部分是核心的动态规划逻辑。外层循环遍历所有奇数 i,表示当前考虑的节点数。内层循环遍历所有可能的左子树节点数 j,并计算对应的右子树节点数 i - 1 - j。然后,根据状态转移方程 dp[i] = sum(dp[j] * dp[i - 1 - j]) 更新 dp[i],并在每次计算时对结果取模。

  5. 返回结果

    java

    return dp[n];

    最后,返回 dp[n],即有 n 个节点时可以构成的好二叉树的数量。

关键点

  1. 动态规划:通过 dp 数组存储中间结果,避免重复计算。
  2. 状态转移方程dp[i] = sum(dp[j] * dp[i - 1 - j]),表示将 i 个节点分解为根节点和左右子树的组合。
  3. 取模操作:在每次计算时对结果取模,防止整数溢出。

通过这些步骤,代码能够正确计算出给定 n 个节点时可以构成的好二叉树的数量。