计算大数字的乘积

时间:2018-05-20 14:17:31

标签: c# algorithm complexity-theory

我试图计算

problem

其中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]时,剩下的一半计算与上半年的产品是否相同?

3 个答案:

答案 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)

你也可以缓存因子。