题目描述
给你一个整数
n
,求恰由n
个节点组成且节点值从1
到n
互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。
示例1
输入:n = 3 输出:5
示例2
输入:n = 1 输出:1
做题思路
给定一个有序序列1…n,为构建出一棵二叉树,我们可以遍历每个数字i,将该数字作为树根,将1…(i-1)序列作为左子树,将(i+1)…n序列作为右子树,接着我们可以按照同样的方式递归构建左子树和右子树。因此原问题可以分解成规模较小的两个子问题,且子问题的解可以复用,所以用动态规划求解。
算法
1. 定义两个函数:
(1) dp(n):长度为n的序列能构成的不同二叉搜索树的个数。
(2) f(i,n):以i为根、序列长度为n的不同二叉搜索树的个数(1<=i<=n)。
2. 由两个函数的含义我们可以得出dp(n)是对遍历所有i(1<=i<=n)的f(i,n)之和。
3. 边界条件:dp(0)=1,dp(1)=1。
即当序列长度为1(只有根)或为0(空树)时,只有一种情况。
4. dp(n)可以从f(i,n)得到(见2),而f(i,n)又会递归地依赖于dp(n)。
(1)创建以i为根、长度为n的不同二叉搜索树,整个序列为[1…n],我们需要从左子序列[1…i-1]构建左子树,从右子序列[i+1…n]构建右子树,然后将它们组合(即笛卡尔积)。
(2)将构建不同左子树的数量表示为dp(i-1),构建不同右子树的数量表示为dp(n-i),因为dp(n)和序列的内容无关,只和序列的长度有关,我们可以得到以下公式:
f(i,n)=dp(i-1)*dp(n-1)
5. 将2中公式和4中公式结合,可以得到:
dp(n)是对遍历所有i(1<=i<=n)的dp(i-1)*dp(n-i)之和
代码
class Solution {
public int numTrees(int n) {
int[] dp=new int[n+1];//dp[i]代表i个节点所对应的二叉搜索树的种数
dp[0]=1;//0个节点的二叉搜索树的种数为1
dp[1]=1;//1个节点的二叉搜索树的种数为1
for(int i=2;i<=n;i++){
for(int j=1;j<=i;j++){
dp[i]+=dp[j-1]*dp[i-j];
}
}
return dp[n];
}
}