题目:
求N个结点能够组成的二叉树的个数(2<=N<=1000)。
例:
输入:
3
输出:
5
分析:看别人的博文说是卡特兰数;我首先想到的是找规律,用递推公式求解,因为我不知道卡特兰数; 寻找出规律之后 当然这里结果可能会超过long long的表示范围,要处理大数问题;
先分析规律,假设n个结点能够组成的二叉树数量为f(n),根节点是固定的,假设左子树有i(0<=i<=n-1)个结点,则右子树有n-1-i个结点,此时可能组成的二叉树数量为f(i) * f(n-1-i);所以有:
f(n) = f(0) * f(n-1) + f(1) * f(n-1-1) + … + f(n-1) * f(n-1-(n-1))
= f(0) * f(n-1) + f(1) * f(n-2) + … + f(n-1) * f(0)
但是计算一下复杂度,用上面的式子求f(n)的复杂度为O(n2),处理大数时时间复杂度为O(n),程序总的时间复杂度为O(n3);这个时间复杂度肯定是要超时了;此时我无奈的发现,不用卡特兰数是没办法解题了;
上面的式子进一步推导,得到递推公式(当然请原谅我并没有去推导,我觉得自己在考场上也不可能推导出来):
f(n)= f(n-1)(4n-2)/(n+1)
我们不妨再看一看卡特兰数的通项公式:
f(n)=C(n, 2n)/(n+1) = (2n)!/((n!)(n+1)!)
关于卡特兰问题的讲解我在知乎上看到一篇很不错,可以去看看,
知乎-卡特兰数.
但是!递推公式里面里面有除法,通项公式里面也有除法!难道我不会JAVA的话,要在考场上手撸一遍大数的加法,乘法,还有除法嘛?!
算了算了,我还是抛弃卡特兰数吧,毕竟我不太会写大数除法,代码量太大了;2<=n<=100这个范围内,还是可以正确的,想拿满分,等我以后进一步学习吧。
#include<iostream>
using namespace std;
struct bigInteger {
int digit[1010], size;
bigInteger() {
memset(digit, 0, sizeof(digit));
size = 0;
}
void set(string str) {
int L = str.length