LintCode :不同的二叉查找树
题目
给出 n,问由 1…n 为节点组成的不同的二叉查找树有多少种?
样例
给出n = 3,有5种不同形态的二叉查找树:
1 3 3 2 1
\ / / / \ \
3 2 1 1 3 2
/ / \ \
2 1 2 3
思路
这里我们可以采用卡特兰树的方法,关于卡特兰树大家可以去维基百科卡特兰树看看。这里面刚好有提到用卡特兰树解决二叉查找树的方法,那为什么可以解决好像没说,那这里我就来简单的说一下。
卡特兰树的递推定义是这样的
Cn+1=C0∗Cn+C1∗Cn−1+...+Cn−1∗C1+Cn∗C0
,这样是不是看起来很像n+1个节点的二叉树,左边有零个节点右边有n个节点的情况加上左边一个节点右边n-1各节点的情况加上。。。以此类推就可以计算出n+1个节点的二叉树有多少种情况了。然后这里给出通项公式
Cn=C(2n,n)/(n+1)
,这里
Cn
就是我们要求的个数。
代码
int numTrees(int n) {
unsigned long long up = 1;
for(int i = 0; i < n; i++)
if(i % 2 == 1)
up *= 2 * n - i;
else
up *= 2;
unsigned long long down = 1;
for(int i = 0; i < n / 2; i++)
down *= n / 2 - i;
return up / down / (n + 1);
}
(哦,对了,这里为了处理阶乘溢出的问题在求阶乘的时候做了一些处理。因为分母是n!*n!分子是2n!,所以第一步约分之后分子剩下的是2n*(2n-1)*…*(n+2)*(n+1),分母则是n!,然后因为分子分母长度一样,数值上2n又是n的两倍,所以分子的偶数部分是可以跟分母消掉后只剩下2的,分子部分消掉后其实就只剩下n / 2!这一部分了,这样处理之后计算阶乘就不会溢出了。)