问题
题目:[不同的二叉查找树]
思路
这个题还是不错的,从找规律入手。本质是分治法,发现重复子问题。然后DP优化。整体的思路还是很清晰的。
主要参考了这篇链接[n个不同节点构成多少不同的二叉搜索树],讲的很清楚。
当N=1时,毫无疑问,只有一种形态。不放记f(1)为N个节点时的二叉树形态。
当N=2时,固定一个根节点,那么剩下的一个节点,要么在左枝,此时右枝为空;要么在右枝,此时左枝为空。所以f(2) = f(1)f(0) + f(0)f(1).
当N=3时,还是固定根节点。那么,左右枝可能的节点数为一下几种情况。
left = 2, right = 0;
left = 1, right = 1;
left = 0, right = 2;
那么他们相应的分支形态个数为:
f(2)*f(0);
f(1)f(1);
f(0)f(2);
所以,N=3时有f(3) = f(2)f(0) + f(1)f(1) + f(0)f(2);
综上,f(N) = f(N-1)f(0) + f(N-2)f(1) + … f(0)f(N-1)
这题是DP的一道好题啊。
状态定义:F[i]代表节点数为i时的分支形态数目;
初始化:F[0]=F[1] = 1;
转台转移:f(N) = f(N-1)f(0) + f(N-2)f(1) + … f(0)f(N-1)
结果:F[N]
这个题本质是分治的思路,利用节点数对情况进行划分,很巧妙。
多说一句,这个题的公式是catalan数。(http://blog.csdn.net/hackbuteer1/article/details/7450250).
百度百科也给了定义:
令h(0)=1,h(1)=1,catalan数满足如下递推关系式 :
h(n)= h(0)*h(n-1)+h(1)*h(n-2) + … + h(n-1)*h(0) (n>=2)
解析解为:
h(n)=C(2n,n)/(n+1) (n=0,1,2,…)
h(n)=c(2n,n)-c(2n,n-1)(n=0,1,2,…)
怎么证参考这个链接[ Catalan数——卡特兰数]
其实上面这个题我觉得不算Catalans数的应用,他们两只是公式一样。
真正比较好的理解还是入栈出栈的合法次序问题,这是个好问题。
代码
class Solution {
public:
/**
* @paramn n: An integer
* @return: An integer
*/
int numTrees(int n) {
// write your code here
return catalan(n);
}
private:
int catalan(int n){
vector<int> dp(n+1, 0);
dp[0] = dp[1] = 1;
for(int i = 2; i <= n; ++i){
for(int j = 0; j < i; ++j){
dp[i] += dp[j]*dp[i-1-j];
}
}
return dp[n];
}
};
下面这段代码不行,因为到N=10的时候就不行了。因为20!太大了。
所以,如果让我写catalan数的计算代码用定义的形式实现。
long long fact(int n){
if(n<0) return -1;
else if(!n) return 1;
else{
long long ans = 1;
for(int i = 2; i <= n; ++i){
ans *= i;
}
return ans;
}
}
int cnk(int n, int k){
return (int)(1.0/fact(k)/fact(n-k)*fact(n));
}
int catalan1(int n){
return cnk(2*n, n)/(n+1);
}