96. 不同的二叉搜索树

动态规划

解题思路

  1. 确定 dp 数组以及下标的含义dp[i] 的含义为 1i 为节点组成的二叉搜索树的个数为 dp[i]

  2. 确定递推公式:状态转移方程 dp[i] += dp[j - 1] * dp[i - j]j-1j 为头结点左子树节点数量 (由于是二叉搜索树,左节点 < 根节点 < 右节点,则左子树数量为 j-1 个)i - j 为以 j 为头结点右子树节点数量 (由于是二叉搜索树,左节点 < 根节点 < 右节点,则右子树数量为 i-j 个)

    • n1 的时候有一棵树,n2 有两棵树;
    • 来看看 n3 的时候
    • dp[3] 就是 元素1为头结点搜索树的数量 + 元素2为头结点搜索树的数量 + 元素3为头结点搜索树的数量
  3. 如何初始化 dp 数组dp[0] = 1,从递归公式上来讲,如果 dp[0] = 0 那么乘法的结果就都变成 0 了;

  4. 确定遍历顺序:节点数为 i 的状态是依靠 i 之前节点数的状态,所以遍历 i 一定是从前向后遍历;

  5. 举例推导 dp 数组

    节点数量 n 0 1 2 3 4 5
    1i 为节点组成的二叉搜索树的个数为 dp[i] 1 1 2 5 14 42

复杂度

  1. 时间复杂度:O(n^2)

  2. 空间复杂度:O(n)

代码实现

const numTrees = (n) => {
    // 1.声明 dp 数组
    let dp = new Array(n + 1).fill(0);

    // 2. 初始化 dp 数组
    dp[0] = 1;
    dp[1] = 1;

    // 3. 根据递推公式,更新矩阵 dp[i] 的值
    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];
};
打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

中午好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. 动态规划
    1. 1.1. 解题思路
    2. 1.2. 复杂度
    3. 1.3. 代码实现