计算二项式系数的算法

Nyx*_*Nyx 8 c# algorithm math combinatorics

我需要一种计算组合的方法,而不会耗尽内存.这是我到目前为止所拥有的.

public static long combination(long n, long k) // nCk
{
    return (divideFactorials(factorial(n), ((factorial(k) * factorial((n - k))))));
}

public static long factorial(long n)
{
    long result;
    if (n <= 1) return 1;
    result = factorial(n - 1) * n;
    return result;
}

public static long divideFactorials(long numerator, long denominator)
{
    return factorial(Math.Abs((numerator - denominator)));
}
Run Code Online (Sandbox Code Playgroud)

我已将其标记为C#,但理想情况下,解决方案应该与语言无关.

Bob*_*yan 18

用于计算二项式系数的最佳方法之一我已经看过建议由Mark Dominus提出.与其他一些方法相比,N和K的值越大,溢出的可能性就越小.

public static long GetBinCoeff(long N, long K)
{
   // This function gets the total number of unique combinations based upon N and K.
   // N is the total number of items.
   // K is the size of the group.
   // Total number of unique combinations = N! / ( K! (N - K)! ).
   // This function is less efficient, but is more likely to not overflow when N and K are large.
   // Taken from:  http://blog.plover.com/math/choose.html
   //
   long r = 1;
   long d;
   if (K > N) return 0;
   for (d = 1; d <= K; d++)
   {
      r *= N--;
      r /= d;
   }
   return r;
}
Run Code Online (Sandbox Code Playgroud)

  • @sean 在标准 C# 用法中,无符号整数保留用于位字段或其他特殊用途,因此不要这样做。计算始终以有符号形式进行。当然,如果需要的话,可以随意使用 BigInteger。 (2认同)

Vic*_*jee 8

public static long combination(long n, long k)
    {
        double sum=0;
        for(long i=0;i<k;i++)
        {
            sum+=Math.log10(n-i);
            sum-=Math.log10(i+1);
        }
        return (long)Math.pow(10, sum);
    }
Run Code Online (Sandbox Code Playgroud)

  • 即使原始帖子使用longs,你的返回值应该是double或long double.当你使用双精度进行计算时,将它转换回很长时间是没有意义的,因为答案不一定是100%精确的.它还会限制你的n和k值. (3认同)
  • 这不是一个好的解决方案.例如,组合(52,5)应该返回2598960,而不是2598959.Mark Dominus一个要好得多. (3认同)

Moo*_*oop 8

这是一个与Bob Byran非常相似的解决方案,但是检查了另外两个前提条件来加速代码.

    /// <summary>
    /// Calculates the binomial coefficient (nCk) (N items, choose k)
    /// </summary>
    /// <param name="n">the number items</param>
    /// <param name="k">the number to choose</param>
    /// <returns>the binomial coefficient</returns>
    public static long BinomCoefficient(long n, long k)
    {
        if (k > n) { return 0; }
        if (n == k) { return 1; } // only one way to chose when n == k
        if (k > n - k) { k = n - k; } // Everything is symmetric around n-k, so it is quicker to iterate over a smaller k than a larger one.
        long c = 1;
        for (long i = 1; i <= k; i++)
        {
            c *= n--;
            c /= i;
        }
        return c;
    }
Run Code Online (Sandbox Code Playgroud)