【动态规划-6】96.不同的二叉搜索树

题目描述:

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

示例 1:

复制代码
输入:n = 3
输出:5

示例 2:

复制代码
输入:n = 1
输出:1

解题思路:

方法一:动态规划

核心思路:

状态定义:

dp[i] = 由 i 个节点组成的二叉搜索树的数量。

状态转移:

对于 i 个节点,枚举根节点:

  • 根节点左边有 j 个节点(构成左子树)

  • 根节点右边有 i - 1 - j 个节点(构成右子树)

复制代码
dp[i] = Σ dp[j] × dp[i-1-j],j 从 0 到 i-1

具体过程示例:

n = 3

复制代码
dp[0] = 1(空树)
dp[1] = 1(1个节点)
dp[2] = dp[0]*dp[1] + dp[1]*dp[0] = 1 + 1 = 2
dp[3] = dp[0]*dp[2] + dp[1]*dp[1] + dp[2]*dp[0] = 2 + 1 + 2 = 5 ✅

枚举根节点:

  • 根=1:左0个,右2个 → dp[0] * dp[2] = 2

  • 根=2:左1个,右1个 → dp[1] * dp[1] = 1

  • 根=3:左2个,右0个 → dp[2] * dp[0] = 2

总计:2 + 1 + 2 = 5 ✅

代码实现:

cpp 复制代码
class Solution {
public:
    int numTrees(int n) {
        vector<int> dp(n + 1, 0);
        dp[0] = 1;  // 空树
        dp[1] = 1;  // 1个节点
        
        for (int i = 2; i <= n; i++) {
            for (int j = 0; j < i; j++) {
                dp[i] += dp[j] * dp[i - 1 - j];
            }
        }
        
        return dp[n];
    }
};

复杂度分析:

维度 复杂度 说明
时间复杂度 O(n²) 双重循环
空间复杂度 O(n) dp 数组

方法二:卡特兰数

核心思路:

dp[n] 就是卡特兰数 C_n:

复制代码
C_n = C(2n, n) / (n + 1)

代码实现:

cpp 复制代码
class Solution {
public:
    int numTrees(int n) {
        long long result = 1;
        for (int i = 1; i <= n; i++) {
            result = result * (n + i) / i;
        }
        return result / (n + 1);
    }
};

更安全的写法:

cpp 复制代码
class Solution {
public:
    int numTrees(int n) {
        long long C = 1;
        for (int i = 0; i < n; i++) {
            C = C * 2 * (2 * i + 1) / (i + 2);
        }
        return (int)C;
    }
};

复杂度分析:

维度 复杂度 说明
时间复杂度 O(n) 一次循环
空间复杂度 O(1) 只用常数个变量

两种方法对比:

方法 时间复杂度 空间复杂度 推荐度
动态规划 O(n²) O(n) ⭐⭐⭐⭐⭐
卡特兰数 O(n) O(1) ⭐⭐⭐⭐

动态规划更通用(能处理变种),卡特兰数更快但需要知道公式。

关键细节:

1. 为什么 dp[0] = 1?

空树也算一种情况。当根节点的左子树或右子树为空时,需要 dp[0] = 1 来保证乘法正确。

2. 为什么是 dp[j] * dp[i-1-j]?

  • 左子树有 j 个节点,有 dp[j] 种结构

  • 右子树有 i-1-j 个节点,有 dp[i-1-j] 种结构

  • 左右子树独立,所以用乘法

3. 卡特兰数的其他应用

  • 括号匹配数

  • 出栈序列数

  • 凸多边形三角划分

  • 满二叉树计数

总结:

要点 说明
核心思想 枚举根节点,左右子树独立
状态转移 dp[i] = Σ dp[j] × dp[i-1-j]
时间复杂度 O(n²)
空间复杂度 O(n)
相关推荐
丘山望岳1 天前
单调栈和单调队列
数据结构
Fuyo_11191 天前
C++ AVL树保姆级详解:从平衡因子到四大旋转机制
java·c++·算法
jktantan1 天前
每个节点 41 字节:把一棵百万节点树拆进 14 个 typed array
前端·javascript·vue.js·算法·typescript
揽星河..1 天前
【C语言】猜数字游戏
c语言·算法·游戏
傲世仙尊1 天前
继承-类设计层次复用切片转换与菱形继承的死结
c++
架构师伯子明1 天前
FFmpeg C++学习(一):编译和demo
开发语言·c++·学习
LabVIEW开发1 天前
CTM-3 红外测温仪 + LabVIEW 温度怎么测?
算法·labview·测试·labview程序
纪念 2291 天前
C++算法(六)
开发语言·c++·算法
ShineWinsu1 天前
对于Qt:QCheckBox常见属性的详细解析
c++·qt·面试·笔试·gui·qcheckbox·多选框
Dumbness1 天前
UIA 读微信群消息没有 id,怎么判断哪条是新的:后缀对齐在翻历史和撤回时整屏重报
python·算法