Arcane是Java中的Prime方法

时间:2012-10-03 19:42:34

标签: java regex primes

考虑以下方法:

public static boolean isPrime(int n) {
    return ! (new String(new char[n])).matches(".?|(..+?)\\1+");
}

我从未成为正规表达大师,所以任何人都可以完全解释这种方法是如何运作的吗? 此外,与确定整数是否为素数的其他可能方法相比,它是否有效?

3 个答案:

答案 0 :(得分:10)

首先,请注意,此正则表达式适用于一元计数系统中表示的数字,即

1       is 1
11      is 2
111     is 3
1111    is 4
11111   is 5
111111  is 6
1111111 is 7

等等。实际上,任何字符都可以使用(因此表达式中的. s),但我会使用“1”。

其次,请注意此正则表达式匹配复合(非素数)数字;因此否定会检测到素性。


<强>解释

表达式的前半部分,

.?

表示字符串“”(0)和“1”(1)是匹配的,即。不是素数(根据定义,though arguable。)

下半场用简单的英语说:

  

匹配长度至少为2的最短字符串,例如“11”(2)。现在,看看我们是否可以通过重复它来匹配整个字符串。 “1111”(4)匹配吗? “111111”(6)是否匹配? “11111111”(8)是否匹配?等等。如果没有,则再次尝试下一个最短的字符串“111”(3)。等

现在您可以看到,如果原始字符串无法与其子字符串的多个匹配,那么根据定义,它是如此!

顺便说一下,非贪婪的算子?是使“算法”从最短的开始算起来的原因。


<强>效率:

这很有趣,但肯定没有效率,各种论点,其中一些我将在下面合并:

  • 正如@TeddHopp指出的那样,众所周知的Eratosthenes筛选方法不会费心去检查4,6和9的整数倍,在检查2的倍数时已经“访问过”了唉,这种正则表达式方法详尽地检查了每个较小的整数。

  • 正如@PetarMinchev所指出的,一旦达到数字的平方根,我们就可以将多重检查方案“短路”。我们应该能够因为一个因子大于而不是平方根必须与一个因子小于而不是平方根(因为否则两个因子大于平方根会产生一个产品大于数量),如果存在这个更大的因素,那么我们应该已经遇到(并因此匹配)较小的因素。

  • 正如@Jesper和@Brian所说,从非算法的角度来看,考虑正则表达式如何通过分配内存来存储字符串例如< / em> char[9000]为9000.嗯,这很容易,不是吗? ;)

  • 正如@Foon所指出的那样,存在概率方法,对于较大的数字可能更有效,尽管它们可能并不总是正确的(改为伪随机)。但也存在确定性测试,这些测试100%准确并且比基于筛选的方法更有效。 Wolfram's有一个很好的总结。

答案 1 :(得分:5)

素数的一元特征及其工作原理已经涵盖。所以这是使用传统方法和这种方法的测试:

public class Main {

    public static void main(String[] args) {
        long time = System.nanoTime();
        for (int i = 2; i < 10000; i++) {
            isPrimeOld(i);
        }
        time = System.nanoTime() - time;
        System.out.println(time + " ns (" + time / 1000000 + " ms)");
        time = System.nanoTime();
        for (int i = 2; i < 10000; i++) {
            isPrimeRegex(i);
        }
        time = System.nanoTime() - time;
        System.out.println(time + " ns (" + time / 1000000 + " ms)");
        System.out.println("Done");
    }

    public static boolean isPrimeRegex(int n) {
        return !(new String(new char[n])).matches(".?|(..+?)\\1+");
    }

    public static boolean isPrimeOld(int n) {
        if (n == 2)
            return true;
        if (n < 2)
            return false;
        if ((n & 1) == 0)
            return false;
        int limit = (int) Math.round(Math.sqrt(n));
        for (int i = 3; i <= limit; i += 2) {
            if (n % i == 0)
                return false;
        }
        return true;
    }
}

此测试计算从2开始,数字是否为9,999以上。这是在相对强大的服务器上的输出:

8537795 ns (8 ms)
30842526146 ns (30842 ms)
Done

一旦数字变得足够大,它就非常低效。 (对于高达999,正则表达式运行大约400毫秒。)对于小数字,它速度很快,但是以传统方式生成高达9,999的素数仍然比以前生成高达99的素数更快( 23毫秒)。

答案 2 :(得分:2)

这不是检查数字是否为素数的真正有效方法(它检查每个除数)。

一种有效的方法是检查最多sqrt(number)的除数。如果你想确定数字是否是素数,那就是这样。否则有概率素性检查更快,但不是100%正确。