问题描述
给定一个整数 n,求以 1 … n 为节点组成的二叉搜索树有多少种?
示例
输入: 3
输出: 5
解释:
给定 n = 3, 一共有 5 种不同结构的二叉搜索树:
1 3 3 2 1
\ / / / \ \
3 2 1 1 3 2
/ / \ \
2 1 2 3
思路
这题我想用95题的思路,构建出来,然后统计最外层的树的个数。(时间复杂度太高了) 不出意外收获了LTE.
总感觉有什么不对,感觉有什么规律。对于95题,我们是把每个结点都当做根结点,在它左边的结点当做它的左子树的根,在它右边的结点当做它的右子树的根。
这样的话,其实对于固定长度的序列来说,生成的树的数目都是一样的。
也就是说:如果一个序列的长度为3,别管序列中存储的值是什么,那么他们生成的二叉搜索树的数量是确定的。
可见,问题可以分解成规模较小的子问题。因此,我们可以存储并复用子问题的解。为啥?以序列长度为3为例:
这个序列可生成的树数为:
以第一个位置的元素为根,以第二个位置的元素为根,以第三个元素为根。 所有的数加起来。
而以第一个位置的元素为根,则右边两个数是它的右子树。 右子树长度为2,它的可生成的树数为: 以第一个位置的元素为根,以第二个位置的元素为根。加起来。
而这个第一个位置元素为根,第二个元素为右子树的情况,只有一种。
第二个位置为根,第一个元素为左子树的情况,只有一种。
所以我们得到长度为2的序列的树数为2,存储下来。直接给上层使用。
我们用res数组来存储,res[i]为长度为i的序列的二叉搜索树的个数。
总结一下就是,为了以 3 为根从序列 [1, 2, 3, 4, 5, 6, 7] 构建二叉搜索树,我们需要从左子序列 [1, 2] 构建左子树,从右子序列 [4, 5, 6, 7] 构建右子树,然后将它们组合(即笛卡尔积)。而左子序列[1,2]构建的左子树的二叉搜索树个数等于res[2], [4, 5, 6, 7] 对应res[4]。乘起来即可。为啥呢?左子树有这么多种,右子树有这么多种,任意组合就是个树。 所以是笛卡尔积(左边集合中的所有值分别于右边集合中的所有值都相乘一遍)。
(方法一)
方法一在数学里叫做卡特兰数。我们可以直接用公式来做。
- C0 = 1
根据这两个公式,我们可以推出来。(方法二)
方法一
public int numTrees1(int n) {
int[] res = new int[n+1];
res[0] = 1;
res[1] = 1;
for(int curIndex = 2; curIndex < res.length; curIndex++){
for(int j = 0; j < curIndex; j++){
res[curIndex] += res[j]*res[curIndex-j-1];
}
}
return res[n];
}
方法二
public int numTrees(int n){
// 防止公式计算过程中溢出,python不需要这样
long res = 1;
for(int i = 0; i < n; i++){
res = 2*(2*i+1)*res/(i+2);
}
return (int)res;
}