题目描述

✅ 96. 不同的二叉搜索树

image-20260928201025649

题意分析

使用数值为 1 到 n 的全部节点,每个值恰好使用一次,统计能构成多少棵结构不同的二叉搜索树。只需要返回数量,不需要创建或返回这些树。

二叉搜索树要求左子树中的值都小于根,右子树中的值都大于根。选择根之后,左右两侧分别包含哪些值就已经确定;需要继续选择的,是各自的子树结构。

解法:Catalan 动态规划

核心思路

[!blue]

固定根的位置后,左侧较小的键只能放入左子树,右侧较大的键只能放入右子树。两侧各自可以独立构造,再连接到同一个根上,因此总数可以按根的位置分类计算。

定义 dp[nodes] 表示由 nodes 个互不相同、有序的键构成二叉搜索树的方案数。这里不需要记录键的具体起止值:同样数量的有序键可以按排名一一对应,数值整体变大或变小不会改变可用的结构。

选择第 root 个键作根时,左子树有 root - 1 个节点,右子树有 nodes - root 个节点。任意一种左子树都能与任意一种右子树配对,因此这个根贡献 dp[root - 1] * dp[nodes - root] 种方案。不同根得到的树不会相同,把所有根的贡献相加即可。

令 dp[0] = 1,表示空子树是一种合法的选择,而不是没有方案。当根位于最左端或最右端时,一侧为空,仍应保留另一侧所有结构,乘以 1 才符合这个含义。

按节点数从少到多计算,每次转移依赖的左右规模都小于当前规模,所需答案已经算出。这一递推得到的数列称为卡特兰数,最终返回 dp[n]。

解题步骤

  1. 创建长度为 n + 1 的计数数组,初始化 dp[0] = 1。
  2. 依次计算 nodes = 1 到 n 的结构数量。
  3. 对每个规模枚举根的排名 root = 1 到 nodes,累加 dp[root - 1] * dp[nodes - root]。
  4. 返回 dp[n]。

代码实现

class Solution {
    public int numTrees(int n) {
        int[] dp = new int[n + 1];

        // 空子树也有一种构造,作为左右组合计数的乘法单位。
        dp[0] = 1;

        for (int nodes = 1; nodes <= n; nodes++) {
            for (int root = 1; root <= nodes; root++) {
                // 固定根后左右构造独立相乘,不同根的情况再相加。
                dp[nodes] += dp[root - 1] * dp[nodes - root];
            }
        }

        return dp[n];
    }
}
func numTrees(n int) int {
    dp := make([]int, n+1)
    // 空子树也有一种构造,作为左右组合计数的乘法单位。
    dp[0] = 1

    for nodes := 1; nodes <= n; nodes++ {
        for root := 1; root <= nodes; root++ {
            // 固定根后左右构造独立相乘,不同根的情况再相加。
            dp[nodes] += dp[root-1] * dp[nodes-root]
        }
    }
    return dp[n]
}

复杂度分析

  • 时间复杂度:$O(n^2)$,规模为 nodes 时枚举 nodes 个根,总转移次数为 $1+2+\cdots+n$。
  • 空间复杂度:$O(n)$,保存 0 到 n 共 n + 1 个规模的答案。

关键点总结

[!green]

  • 子树结构数由节点数量决定,具体数值只需保持大小关系,无须额外记录区间。
  • 同一个根下的左右方案独立组合,所以相乘;不同根对应互斥分类,所以求和。
  • dp[0] = 1 是组合计数中的空选择,保证一侧为空的树也能正常计数。

易错点总结

[!yellow]

  • 将 dp[0] 留为 0,会使涉及空子树的乘积归零,递推无法正确开始。
  • 把左右子树数量相加,会漏掉彼此配对的组合;把不同根的贡献相乘,则会把互斥情况错误组合。
  • 枚举根时必须累加到 dp[nodes],直接赋值只会保留最后一个根的贡献。
  • 根本身不属于任何一侧,左右节点数分别为 root - 1 与 nodes - root,两者之和为 nodes - 1。
  • 题目要求精确数量,且 n <= 19 时结果能放入 32 位有符号整数,不需要取模。

相似题目

题目 难度 关联与区别
95. 不同的二叉搜索树 II 中等 同样枚举根并组合左右子树,本题用数量乘积代替实际构造树。
22. 括号生成 中等 两题的计数都满足卡特兰结构,可对比按根分割与按首个匹配括号分割。
转载与许可
作者
链接 https://hgnulb.github.io/blog/2026/69678908
许可 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!