https://leetcode-cn.com/problems/unique-binary-search-trees/
思路:我们可以计算以每个节点作为根节点的搜索树的数量然后求和。令f(i)表示以i为根的二叉搜索树的个数即有:Sum = f(1) + f(2) + f(3) + f(4) + ... + f(n);
但是我们知道了根节点后,下面的怎么求呢?
因为这是一颗搜索二叉树,左子树上的节点小于根节点,右子树上的节点大于根节点。假设根节点是i,那么它的左子树就有i-1个节点,右子树有n-i个节点。接着我们可以按照同样的方式递归构建左子树和右子树。所以以i为根节点的搜索树f(i),有左子树都种类数 * 右子树的种类个节点。
递归:
class Solution {
public static int numTrees(int n) {
if(n==0 || n==1) return 1;
int sum = 0;
for (int i = 1; i <= n; i++) {
int left = numTrees(i-1);//左子树的种类数
int right = numTrees(n-i);//右子树的种类数
sum+=left*right;
}
return sum;
}
}
效率很低,有很多的重复计算,比如 i-1 = n-i, numTrees(i-1)和numTrees(n-i)算出的结果是一样的,但还是要计算两次。
动态规划:
在上述构建的过程中,由于根的值不同,因此我们能保证每棵二叉搜索树是唯一的。由此可见,原问题可以分解成规模较小的两个子问题,且子问题的解可以复用。因此,我们可以想到使用动态规划来求解本题。
我们可以构造两个函数:sum(i)和f(i,n)
sum(n):表示长度为n的能构成的不同二叉搜索树的个数;
f(i,n):表示以i为根节点,长度为n的不同二叉搜索树的个数;
sum(n)是我们需要的,可以通过f函数求和得到sum
已知:
class Solution {
public static int numTrees(int n) {
int[] sum = new int[n+1];
sum[0] = 1;sum[1] = 1;
//i表示长度,j表示根节点
for (int i = 2; i <=n ; i++) {
for (int j = 1; j <= i; j++) {
sum[i] += sum[j-1] * sum[i-j];
}
}
return sum[n];
}
}
太难了~~