【LeetCode】96.不同的二叉搜索树

88 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第9天,点击查看活动详情

题目

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

示例 1

img

输入:n = 3
输出:5

示例 2

输入:n = 1
输出:1

提示

  • 1 <= n <= 19

题解

思路

因为对于一棵树,总是可以取其子树。我们可以将计算一棵二叉搜索树的种数,转化成由 1 到 n 不同的子节点为根的左右子树的种类之和,所以可以用动态规划。

确定 dp 数组的定义。dp[i] 表示从 1 到 i 不同节点组成的互不相同的二叉搜索树的个数。

确定递推公式。对于一个整数 i,它的二叉搜索树的根节点的值可为 1-i,那么对于根节点为j的二叉搜索树,左子树只能由值为 1-(j-1) 的节点组成,右子树只能由值为 (j+1)-i 的节点组成。对于值为 (j+1)-i 的节点组成的二叉搜索树,它的个数等价于值从 1 开始,节点数与它相等的二叉搜索树的个数。

所以对于以 j 为根节点的二叉搜索树,左子树的个数 dp[j-1]*右子树的个数 dp[i-j] 就为该树的种数,将根节点的值为 1-i 的二叉搜索树的个数相加,就是 i 个节点组成的二叉搜索树的种树。

确定数组初始化。当整数为0时,空节点也可以算作一棵树,所以初始化为 1。

确定遍历顺序。遍历整个数组,因为 dp[i] 的值和前面的值有关。所以要遍历整个数组。在遍历里,让1-i 每个数都作为根节点,将这样的二叉搜索树种类加到 dp[i] 里。

代码

/**
 * @param {number} n
 * @return {number}
 */
var numTrees = function(n) {
    const dp = new Array(n + 1).fill(0);
    dp[0] = 1;
    for(let i = 1; i <= n; i++) {
        // 每个数都当一次根节点
        for(let j = 1; j <= i; j++) {
            dp[i] += dp[j - 1] * dp[i - j];
        }
    }
    return dp[n];
};

结语

业精于勤,荒于嬉;行成于思,毁于随。