模数非常大

时间:2015-10-19 20:08:15

标签: java algorithm optimization numeric

用户将使用标准输入输入2个整数x和y。您需要计算x modulo y(x%y)的余数。

现在,问题在于:

0 <= x <= 10 ^ 100000,(这是“小于或等于”不是箭头)。 0&lt; y&lt; = 100000

我们正在寻找最佳解决方案(时间复杂度)。

我没有在Stackoverflow上找到答案,所以在找到解决方案之后我认为我应该在这里提出这个问题以供将来参考,看看是否有更好的方法。

2 个答案:

答案 0 :(得分:3)

BigIntegerdivideAndRemainder(...)方法,一个返回BigInteger数组,第一个项是除法结果,第二个是余数(这是mod在Java中真正做的)。

<强>更新

包括Mark Dickinson对其他答案的评论:

  

有一个更简单的线性时间算法:设置acc为0,然后依次为x中的每个数字d(从左到右),将d转换为整数并设置acc =(acc * 10 + d )%y。消费数字后,acc就是您的结果。

按照描述实施所有3种算法:

private static int testMarkDickinson(String x, int y) {
    int acc = 0;
    for (int i = 0; i < x.length(); i++)
        acc = (acc * 10 + x.charAt(i) - '0') % y;
    return acc;
}

private static int testHovercraftFullOfEels(String x, int y) {
    return new BigInteger(x).divideAndRemainder(BigInteger.valueOf(y))[1].intValue();
}

private static int testMrM(String x, int y) {
    String s = x;
    while (s.length() >= 7) {
        int len = Math.min(9, s.length());
        s = Integer.parseInt(s.substring(0, len)) % y + s.substring(len);
    }
    return Integer.parseInt(s) % y;
}

使用种子随机数进行测试以进行可验证测试(不想对98765位数进行硬编码):

public static void main(String[] args) {
    Random r = new Random(98765);
    char[] buf = new char[98765];
    for (int i = 0; i < buf.length; i++)
        buf[i] = (char)('0' + r.nextInt(10));

    String x = new String(buf);
    int y = 98765;

    System.out.println(testMarkDickinson(x, y));
    System.out.println(testHovercraftFullOfEels(x, y));
    System.out.println(testMrM(x, y));

    long test1nano = 0, test2nano = 0, test3nano = 0;
    for (int i = 0; i < 10; i++) {
        long nano1 = System.nanoTime();
        testMarkDickinson(x, y);
        long nano2 = System.nanoTime();
        testHovercraftFullOfEels(x, y);
        long nano3 = System.nanoTime();
        testMrM(x, y);
        long nano4 = System.nanoTime();
        test1nano += nano2 - nano1;
        test2nano += nano3 - nano2;
        test3nano += nano4 - nano3;
    }
    System.out.printf("%11d%n%11d%n%11d%n", test1nano, test2nano, test3nano);
}

输出:

23134
23134
23134
    8765773
 1514329736
 7563954071

所有3个产生了相同的结果,但性能上有明显的差异,而M&M先生的更好的解决方案&#34;是最糟糕的。

答案 1 :(得分:-3)

比BigInteger更好的解决方案如下:

1-将x读作字符串,将y读作整数。

2-剪切x左边的前9个字符并将它们转换为整数i。

3-计算i%y并将其附加到x的开头。

从2开始重复4直到x字符串小于7(int的最大长度 - 分隔符的最大长度)。

5-用x的左边连接并计算模数。

此解决方案不限于任何整数长度。