利用正则判断素数
判断素数有很多方法, 比如定义法,费马小定理,米勒-拉宾素性检验,Solovay-Strassen素性判定等。
一、定义法
这种方法利用素数定义来判断素数。
素数又叫质数,质数是指在大于1的自然数中,除了1和它本身以外,不能被其他自然数整除的数。最小的质数是2,它也是唯一的偶数质数,最前面的质数依次排列为:2、3、5、7、11、13、17、19、23、29、31等。
static boolean isPrime(int n) {
if (n <= 1)
return false;
else if (n == 2)
return true;
else if (n % 2 == 0) return false;
for (int i = 3; i <= Math.sqrt(n); i += 2) {
if (n % i == 0) return false;
}
return true;
}
二、费马小定理
费马小定理(Fermat’s little theorem)是数论中的一个重要定理,在1636年提出。如果p是一个质数对于任意a,
1
<
a
<
n
−
1
1 < a < n-1
1<a<n−1 满足
a
n
−
1
≡
1
(
m
o
d
n
)
a^{n-1}\equiv1(mod\ n)
an−1≡1(mod n) 或者
a
n
−
1
a^{n-1}
an−1 %
n
=
1
n=1
n=1
static int power(int a, int n, int p) {
int res = 1;
a = a % p;
while (n > 0) {
if ((n & 1) == 1) res = (res * a) % p;
n = n >> 1; // n = n/2
a = (a * a) % p;
}
return res;
}
static boolean isPrime(int n, int k) {
if (n <= 1 || n == 4) return false;
if (n <= 3) return true;
while (k > 0) {
int a = 2 + (int) (Math.random() % (n - 4));
if (power(a, n - 1, n) != 1) return false;
k--;
}
return true;
}
三、利用正则判断素数
public static void main(String[] args) {
System.err.println(prime(0));
// false
System.err.println(prime(1));
// true
System.err.println(prime(2));
// true
System.err.println(prime(3));
// true
System.err.println(prime(5));
// false
System.err.println(prime(8));
// true
System.err.println(prime(13));
// false
System.err.println(prime(14));
// false
System.err.println(prime(15));
}
public static boolean prime(int n) {
return !new String(new char[n]).matches(".?|(..+?)\\1+");
}
改算法的精髓在 !new String(new char[n]).matches(".?|(..+?)\\1+");
这行代码。
该函数首先生成n个字符,并尝试查看该字符串是否匹配".?|(..+?)\\1+"
。如果n是素数,则matches函数会返回false,然后!
再将结果反转。
表达式的第一部分.?
是确保1不是素数。因为n等于1或者0的话,String的长度为1或者0,那么.?
会匹配上,经过!
返回false
。最重要的地方在表达式的第二部分括号括起来的部分。(..+?)
以非贪婪模式方式匹配至少两个字符,然后\\1
反向引用(..+?)
匹配到的部分,再利用+
匹配至少一次。
根据定义,素数是一个大于1的自然数,除了1和它本身没有正因子。这意味着如果
a
=
n
×
m
a=n\times m
a=n×m,那么a不是素数。
n
×
m
n\times m
n×m可以进一步解释n个字符重复m次”,这便是正则表达式的原理。使用(..+?)
匹配n个字符长度,然后使用\\1
重复m次。