我试图计算
,
其中C i 是第i个加泰罗尼亚数字。
为了解决这个问题,我从0循环到n并将两个加泰罗尼亚数字的乘积相加:
BigInteger catalanSum = 0;
for (int i = 0; i <= n; i++)
catalanSum += catalan(i) * catalan(n - i);
加泰罗尼亚函数返回二项式系数除以n + 1:
BigInteger catalan(int n)
{
return NchooseK(2 * n, n) / (n + 1);
}
为了计算二项式系数,我使用这个函数:
BigInteger NchooseK(int n, int k)
{
BigInteger res = 1;
if (k > n - k)
k = n - k;
for (int i = 0; i < k; ++i)
{
res *= (n - i);
res /= (i + 1);
}
return res;
}
它可以很好地工作到n = 1000,但是一旦它变得越来越高它真的慢了很多。有什么办法可以优化这个计算吗?
编辑:
我首先使用以下代码片段保存加泰罗尼亚语,加快了计算速度,感谢xanatos回答:
BigInteger[] catalans = new BigInteger[n+1];
BigInteger catalanSum = 0;
for (int i = 0; i <= n; i++)
catalans[i] = catalan(i);
for (int i = 0; i <= n; i++)
catalanSum += catalans[i] * catalans[n - i];
编辑2: 当加泰罗尼亚语[i] ==加泰罗尼亚语[n - i]时,剩下的一半计算与上半年的产品是否相同?
答案 0 :(得分:3)
您正在描述的计算似乎是计算n
Catalan Number的第一个递归关系(当您只使用加泰罗尼亚数字时,您也会不必要地应用二项式计算他们自己在复发)。那个O(n ^ 2)复杂度加上所有二项式计算的复杂性。为什么不使用第二个递归关系?
catalan(0) = 1
catalan(n + 1) = 2*(2*n + 1) / (n + 2) * n
答案 1 :(得分:1)
您可以做两件事:
首先,检查OEIS的序列。你会发现序列有an entry。此条目有一个有用的公式:
2*(2*n-1)*a(n-1) = (n+1)*a(n)
因此,计算加泰罗尼亚语数字可以更有效地完成:
BigInteger lastCatalan = 1;
catalans[0] = lastCatalan;
for(int i = 1; i <= n; ++i)
{
lastCatalan = (2 * (2 * i - 1) * lastCatalan) / (i + 1);
catalans[i] = lastCatalan;
}
第二件事是你的总和是对称的。即,你只需要将一半的条目加起来:
BigInteger catalanSum = 0;
for (int i = 0; i < (n + 1) / 2; i++)
catalanSum += catalans[i] * catalans[n - i];
catalanSum = 2 * catalanSum;
if (n % 2 == 0)
catalanSum += catalans[n / 2] * catalans[n / 2];
在גלעדברקן指出你要找的是n+1
- 加泰罗尼亚数字,这可以大大简化:
BigInteger catalanSum= 1;
for(int i = 1; i <= n + 1; ++i)
catalanSum = (2 * (2 * i - 1) * catalanSum) / (i + 1);
答案 2 :(得分:0)
你也可以缓存因子。