在java中实现choose表示法的好方法是什么?

lqfhib0f  于 2021-06-30  发布在  Java
关注(0)|答案(6)|浏览(428)

... 最好是 java 语。以下是我所拥有的:

//x choose y
public static double choose(int x, int y) {
    if (y < 0 || y > x) return 0;
    if (y == 0 || y == x) return 1;

    double answer = 1;
    for (int i = x-y+1; i <= x; i++) {
        answer = answer * i;
    }
    for (int j = y; j > 1; j--) {
        answer = answer / j;
    }
    return answer;
}

我想知道有没有更好的办法?

8fq7wneg

8fq7wneg1#

此版本不需要 BigInteger 或浮点运算,并且对所有对象都没有溢出错误 n 不到62。62比28是导致溢出的第一对。

public static long nChooseK(int n, int k) {
    k = Math.min(k, n - k);

    if (n < 0 || k < 0)
        throw new IllegalArgumentException();

    if (k == 0)
        return 1;

    long value = n--;

    for (int i = 2; i <= k; i++) {
        value = Math.multiplyExact(value, n--);
        value /= i;
    }

    return value;
}

以下测试证明这是正确的:

@Test
void nChooseKLongVsBigInt() {
    for (int n = 0; n < 62; n++) {
        for (int k = 0; k <= n; k++) {
            assertEquals(nChooseKBigInt(n, k), BigInteger.valueOf(nChooseK(n, k)));
        }
    }
}

private BigInteger nChooseKBigInt(int n, int k) {
    return factorial(n).divide(factorial(k).multiply(factorial(n - k)));
}

private BigInteger factorial(int number) {
    BigInteger result = BigInteger.ONE;

    for (int factor = 2; factor <= number; factor++) {
        result = result.multiply(BigInteger.valueOf(factor));
    }

    return result;
}
8yparm6h

8yparm6h2#

对于
n/((r!)(n-r)!)
使用此(伪代码)

if (R>N) return 0;

long r = max(R, N-r)+1;
if (R==N) return 1;

for (long m = r+1, long d = 2; m <= N; m++, d++ ) {
    r *= m;
    r /= d;
}
return r;
1l5u6lss

1l5u6lss3#

你正在处理的数字将变得相当大,很快就会超过 double 价值观,给你意想不到的错误结果。因此,您可能需要考虑任意精度的解决方案,例如使用 java.math.BigInteger ,不会出现这个问题。

zujrkrfu

zujrkrfu4#

老实说,我看你的情况很清楚。诚然,我会把return语句放在大括号里,因为这是我遵循的惯例,但除此之外,它看起来和它得到的一样好。
我想我可能会颠倒第二个循环的顺序,这样两个循环都是上升的。
正如greg所说,如果您需要获得大量数据的准确答案,您应该考虑其他数据类型。考虑到结果应该始终是整数,您可能需要选择 BigInteger (尽管有所有的除法,结果始终是整数):

public static BigInteger choose(int x, int y) {
    if (y < 0 || y > x) 
       return BigInteger.ZERO;
    if (y == 0 || y == x) 
       return BigInteger.ONE;

    BigInteger answer = BigInteger.ONE;
    for (int i = x - y + 1; i <= x; i++) {
        answer = answer.multiply(BigInteger.valueOf(i));
    }
    for (int j = 1; j <= y; j++) {
        answer = answer.divide(BigInteger.valueOf(j));
    }
    return answer;
}
jucafojl

jucafojl5#

choose(n,k) = n! / (n-k)! k!

你可以在o(k)中做这样的事情:

public static double choose(int x, int y) {
    if (y < 0 || y > x) return 0;
    if (y > x/2) {
        // choose(n,k) == choose(n,n-k), 
        // so this could save a little effort
        y = x - y;
    }

    double denominator = 1.0, numerator = 1.0;
    for (int i = 1; i <= y; i++) {
        denominator *= i;
        numerator *= (x + 1 - i);
    }
    return numerator / denominator;
}

编辑if x 以及 y 如果你的答案是大的,那么你的溢出速度会更慢(即,对于较大的x&y值是安全的),如果你在进行以下操作时除以你的答案:

double answer = 1.0;
    for (int i = 1; i <= y; i++) {
        answer *= (x + 1 - i);
        answer /= i;           // humor 280z80
    }
    return answer;
2exbekwf

2exbekwf6#

我用c#编写了这个代码,但我试图使它尽可能适用于java。
来源于这些资料,再加上我的一些小东西。
http://blog.plover.com/math/choose.html
http://blog.plover.com/math/choose-2.html
代码:

public static long BinomialCoefficient(long n, long k)
{
    if (n / 2 < k)
        return BinomialCoefficient(n, n - k);

    if (k > n)
        return 0;

    if (k == 0)
        return 1;

    long result = n;
    for (long d = 2; d <= k; d++)
    {
        long gcd = (long)BigInteger.GreatestCommonDivisor(d, n);
        result *= (n / gcd);
        result /= (d / gcd);
        n++;
    }

    return result;
}

相关问题