携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第9天,点击查看活动详情
题目
给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。
示例 1
输入: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];
};
结语
业精于勤,荒于嬉;行成于思,毁于随。