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

50 阅读2分钟

解题思路细化

  1. 理解好二叉树的定义

    • 好二叉树中的每个节点要么没有孩子,要么有两个孩子。
    • 这意味着每个非叶子节点都有两个子节点,且树的节点总数 n 必须是奇数(因为每个非叶子节点贡献两个子节点,加上自身一个节点,总数为奇数)。
  2. 动态规划方法

    • 我们可以使用动态规划来解决这个问题。定义 dp[i] 为有 i 个节点时可以构成的好二叉树的数量。
    • 初始条件:dp[1] = 1(只有一个节点时,只有一种树结构)。
    • 状态转移方程:对于每个奇数 i,我们可以将 i 个节点分成根节点和左右子树。假设左子树有 j 个节点,右子树有 i-1-j 个节点(因为根节点占用一个节点),则有:
      [
      dp[i] = \sum_{j=1}^{i-1} dp[j] \times dp[i-1-j]
      ]
    • 最终答案为 dp[n]
  3. 取模运算

    • 由于结果需要对 10^9 + 7 取模,我们在计算过程中需要对每一步的结果取模。

关键思路提示

  1. 初始条件

    • dp[1] = 1,因为只有一个节点时,只有一种树结构。
  2. 状态转移方程

    • 对于每个奇数 i,计算 dp[i] 的值。
    • 使用两层循环:外层循环遍历所有奇数 i,内层循环遍历所有可能的左子树节点数 j(从1到i-1,且 j 为奇数)。
    • 计算 dp[i] 时,累加所有可能的 dp[j] * dp[i-1-j] 的值,并对结果取模 10^9 + 7
  3. 边界条件

    • 如果 n 是偶数,直接返回0,因为好二叉树的节点数必须是奇数。
public class Main {
    public static int solution(int n) {
        // 如果n是偶数,直接返回0,因为好二叉树的节点数必须是奇数
        if (n % 2 == 0) return 0;
        
        // 定义dp数组,dp[i]表示有i个节点时可以构成的好二叉树的数量
        int[] dp = new int[n + 1];
        int MOD = 1000000007;
        
        // 初始条件
        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;
            }
        }
        
        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);
    }
}

关键步骤

  • 初始条件dp[1] = 1
  • 状态转移:对于每个奇数 i,计算 dp[i] 的值。
  • 取模运算:在每次计算 dp[i] 时,对结果取模 10^9 + 7

通过上述思路和代码框架,你可以逐步实现代码并验证其正确性。