96-不同的二叉搜索树
一、题目
给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。
二、分析
假设n个节点存在二叉排序树Q的个数是G(n),令f(i)为以i为根的二叉搜索树的个数,则
G(n)-f(1)+f(2)+f(3)+f(4)+...+f(n)
当i为根节点时,其左子树节点个数为i-1个,右子树节点点n-i,则:
f(i)=G(i-1)*G(n-i)
所以n个节点存在的二叉排序树的个数可以拆分成每个节点作为根节点对应的排序树这样的小问题
所以采用动态规划思路
(1)确定dp数组及下标含义
dp[i]
:表示1到i为节点组成的二叉树的个数
(2)确定递推表达式
dp[i] += dp[j-1]*dp[i-j];
j-1为j为头结点左子树节点数量,ij为以j为头结点右子树节点数量
(3)确定dp初始化
初始时1个节点对应1,空节点对应1:dp[1]=1,dp[0]=1
(4)确定遍历顺序
由递推表达式,确定是由前向后遍历,每一个i节点的个数都依赖于1的情况
for (int i = 2; i <= n; i++) {
for (int j = 1; j <= i; j++) {
dp[i] += dp[j-1] * dp[i - j];
}
}
三、实现
class Solution {
public int numTrees(int n) {
// 使用动态规划求n个节点 节点值从1~n的二叉搜索树个数
// 利用一维数组实现dp[i]表示根节点为i 节点值为1~n的二叉搜索树个数
// 定义一维数组
int[] dp = new int[n + 1];
// 初始化一维数组
// 空节点和一个节点的二叉搜索树初始化为1
dp[0] = 1;
dp[1] = 1;
// 遍历2~n dp[i]表示i为根节点的二叉搜索树个数
for(int i=2; i<=n; i++){
// 遍历1~i 以每一个值都作为根节点
for(int j=1; j<=i; j++){
// 对于第i个节点 需要考虑1作为根节点知道i作为根节点的情况 所以需要累加
// 更新dp[i]:i为根节点的二叉搜索树个数
// 一共i个节点 对于根节点j 左子树个数为j-1个 右子树个数为i-j个
// dp[j-1]:表示j为根节点时左子树二叉搜索树的个数
// dp[i-j]:表示j为根节点时右子树二叉搜索树的个数
dp[i] += dp[j-1] * dp[i-j];
}
}
// 循环结束 1~n的互不相同的二叉搜索树为最后一个元素
return dp[n];
}
}
四、总结
该题的关键是考虑到,对于节点i时, 需要考虑对于(1,i),根节点为…到根节点为i的所有情况
for (int j = 1; j <= i; j++) {
//对于第i个节点,需要考虑1作为根节点直到i作为根节点的情况,所以需要累加
//一共i个节点,对于根节点j时,左子树的节点个数为j-1,右子树的节点个数为i-j
dp[i] += dp[j - 1] * dp[i - j];
}
对于根节点j,左子树的个数为j-1,右子树的个数ij,所以总的个数为:
dp[i] += dp[j - 1] * dp[i - j];