质数:只能被 1
和自身整除的的自然数,1
既不是质数也不是合数。
质数定理:1
到 n
中最多有 n/log(n)
个质数。
质数判定通常有两类方法:试除法和筛质数。
试除法,顾名思义,对于 n
,检查所有 2 ≤ m < n
,是否存在 m
是 n
的质数,若不存在则说明 n
是质数。试除法用于判断一个数是不是质数。
筛质数,筛选出小于等于 n
的质数/非质数。筛质数用于判断一批数是不是质数,常用的筛质数方法有埃氏筛法和线性筛法。
试除法
// 试除法
bool isPrime(int x) {
if (x < 2)return false;
for (int i = 2; i <= x / i; i++) {
if(x%i==0)return false;
}
return true;
}
bool isPrime(int x) {
if (x < 2)return false;
for (int i = 2, k = sqrt(x); i <= k; i++) {
if (x % i == 0)return false;
}
return true;
}
时间复杂度:O(√n)
空间复杂度:O(1)
埃氏筛法
基本思想:假设求范围小于等于 n
的质数,对于 2≤m≤n
的每个数 m
,将其 k
倍数(k>1
)筛掉,剩下的就是质数。
// primes 记录已找到的每个质数
int primes[N], idx;
// notPrime[i]=true 表示 i 不是质数
bool notPrime[N];
void getPrimes(int n) {
for (int i = 2; i <= n; ++i) {
if (!notPrime[i]) {
// 当轮到 i 时,如果 i 没有被筛掉,则 i 必为质数
primes[idx++] = i;
// 当i为质数时才需要筛掉它的倍数
for (int j = i << 1; j <= n; j += i) {
notPrime[j] = true;
}
}
}
}
时间复杂度:O(nlog(log(log(n)))
空间复杂度:O(n)
线性筛法
基本思想:假设求范围小于等于 n
的质数,对于 2≤m≤k
的每个质数 m
,将其 k
倍数筛掉,剩下的就是质数(k
由 2
到 n
)。
// primes 记录已找到的每个质数
int primes[N], idx;
// notPrime[i]=true 表示 i 不是质数
bool notPrime[N];
void getPrimes(int n) {
for (int i = 2; i <= n; ++i) {
if (!notPrime[i]) primes[idx++] = i;
// 筛掉目前所有质数的i倍
for (int j = 0; primes[j] <= n / i; ++j) {
notPrime[primes[j] * i] = true;
if (i % primes[j] == 0)break;
// 当i%pj=0时,pj一定是i的最小质因子,所以,pj一定是pj*i的最小质因子
// 当i%pj!=0时,pj一定小于i的最小质因子,所以,pj一定是pj*i的最小质因子
// 于是每个数只会被其最小质因子筛掉,也即不会重复被筛
}
}
}
时间复杂度:O(n)
空间复杂度:O(n)
END
文章文档:公众号 字节幺零二四
回复关键字可获取本文文档。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。