96. 不同的二叉搜索树
给定一个整数 n,求以 1 … n 为节点组成的二叉搜索树有多少种?
示例:
输入: 3
输出: 5
解释:
给定 n = 3, 一共有 5 种不同结构的二叉搜索树:
1 3 3 2 1
\ / / / \ \
3 2 1 1 3 2
/ / \ \
2 1 2 3
分析
要想知道n个数字组成的二叉搜索树,就需要知道分别以1到n-1每个数字为根有多少种二叉搜索树。
dp[n] = g[1]+...+g[n];
对于每一个数字为根的情况:
g[n] = 左子树的数量*右子树的数量。
构建出来的树的数量和数字无关,比如 1 2 3三个数构建出来的树和5 6 7三个数构建出来的树的数量一样。所以右侧的二叉树的数量,就等于左侧同样数量的二叉树的数量。
所以
g(i) = dp[i-1]*dp[n-(i+1)+1] = dp[i-1]*dp[n-i]
代入dp[n]的公式
dp(n)=dp(0)*dp(n−1)+dp(1)*dp(n−2)+...+dp(n−1)*dp(0)
dp2 = dp0*dp1 + dp1*dp0
dp3 = dp0*dp2 + dp1*dp1 + dp2*dp0
dp5 = dp0*dp4 + dp1*dp3 + dp2*dp2 + dp3*dp1 + dp4*dp0
所以用动态规划,外层循环1到n,记录n个数字能组成多少二叉搜索树。
内层循环0到i-1,计算左右子树的乘积。
代码
class Solution {
public int numTrees(int n) {
//排除特殊情况
if(n == 0) return 1;
int[] dp = new int[n+1];
dp[0] = 1;
dp[1] = 1;
for(int i = 2; i<=n; i++){
for(int j = i-1; j>=0; j--){
dp[i] += (dp[i-j-1]*dp[j]);
}
}
return dp[n];
}
}