Medium

题目描述

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

示例 1:

输入:n = 3
输出:5

示例 2:

输入:n = 1
输出:1

提示:

  • 1 <= n <= 19

解题思路

这道题是经典的卡特兰数问题。我们需要计算由 1 到 n 组成的不同二叉搜索树的数量。

核心思路

对于 n 个节点的二叉搜索树,我们可以选择任意一个节点 i(1 ≤ i ≤ n)作为根节点:

  • 左子树包含节点 1 到 i-1,共 i-1 个节点
  • 右子树包含节点 i+1 到 n,共 n-i 个节点

G(n) 表示 n 个节点能构成的不同二叉搜索树数量,则有递推关系:

G(n) = G(0)×G(n-1) + G(1)×G(n-2) + ... + G(n-1)×G(0)

解法分析

  1. 动态规划解法:使用数组存储中间结果,自底向上计算
  2. 数学公式解法:直接使用卡特兰数公式 C(n) = C(2n,n)/(n+1)
  3. 记忆化递归:递归计算并缓存结果

推荐使用动态规划解法,时间复杂度 O(n²),空间复杂度 O(n),思路清晰易懂。

代码实现

class Solution {
public:
    int numTrees(int n) {
        vector<int> dp(n + 1, 0);
        dp[0] = dp[1] = 1;
        
        for (int i = 2; i <= n; i++) {
            for (int j = 1; j <= i; j++) {
                dp[i] += dp[j - 1] * dp[i - j];
            }
        }
        
        return dp[n];
    }
};
class Solution:
    def numTrees(self, n: int) -> int:
        dp = [0] * (n + 1)
        dp[0] = dp[1] = 1
        
        for i in range(2, n + 1):
            for j in range(1, i + 1):
                dp[i] += dp[j - 1] * dp[i - j]
        
        return dp[n]
public class Solution {
    public int NumTrees(int n) {
        int[] dp = new int[n + 1];
        dp[0] = dp[1] = 1;
        
        for (int i = 2; i <= n; i++) {
            for (int j = 1; j <= i; j++) {
                dp[i] += dp[j - 1] * dp[i - j];
            }
        }
        
        return dp[n];
    }
}
/**
 * @param {number} n
 * @return {number}
 */
var numTrees = function(n) {
    const dp = new Array(n + 1).fill(0);
    dp[0] = dp[1] = 1;
    
    for (let i = 2; i <= n; i++) {
        for (let j = 1; j <= i; j++) {
            dp[i] += dp[j - 1] * dp[i - j];
        }
    }
    
    return dp[n];
};

复杂度分析

复杂度类型分析
时间复杂度O(n²) - 双重循环计算所有状态
空间复杂度O(n) - 使用数组存储中间结果

相关题目