文章目录
- 质数
- 例题列表
- 866. 试除法判定质数(质数的判定)
- 867. 分解质因数()
- 868. 筛质数
- 埃氏筛
- 欧氏筛 / 线性筛
- 相关链接
质数
定义
:质数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。
也就是说一个数 > 1,而且它的因数只有 1 和 它本身,那么它就是质数。
例题列表
866. 试除法判定质数(质数的判定)
https://www.acwing.com/activity/content/problem/content/935/
import java.util.*;
public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
while (n-- != 0) {
int a = sc.nextInt();
System.out.println(isPrime(a)? "Yes": "No");
}
}
static boolean isPrime(int x) {
if (x <= 1) return false;
for (int i = 2; i <= x / i; ++i) { // 注意这里写成 i <= x / i,不要写成 i * i <= x
if (x % i == 0) return false;
}
return true;
}
}
当 n 比较接近 Integer.MAX_VALUE 时,如果使用 i * i <= n, i * i 可能会溢出。所以推荐写成 i <= n / i
。
时间复杂度是 O ( n ) O(\sqrt{n}) O(n)
867. 分解质因数()
质因数(素因数或质因子)在数论里是指能整除给定正整数的质数。
从小到大枚举所有数,(注意
:不需要枚举所有的质数,只要枚举所有的数即可。)
Q:为什么?
A:因为当枚举到 i 时,就意味着已经把从 2 ~ i - 1 的所有质因子都除干净了。(更详细的:当枚举到 i 时,n 中不包含 2 ~ i - 1 中的数字作为因子,所以一定不会和 i 有共同的因子了。)
import java.util.*;
public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
while (n-- != 0) {
divide(sc.nextInt());
}
}
static void divide(int x) {
for (int i = 2; i <= x / i; ++i) {
if (x % i == 0) {
int s = 0;
while (x % i == 0) { // 把 x 中的 i 除干净
s++;
x /= i;
}
System.out.println(i + " " + s);
}
}
if (x > 1) System.out.println(x + " " + 1); // 注意要判断最后剩下的没被除掉的质因数
System.out.println();
}
}
n 中最多只包含 1 个 大于
n
\sqrt{n}
n 的质因子。
所以先枚举出所有小于等于
n
\sqrt{n}
n 的质因子,最后剩下的就是大于
n
\sqrt{n}
n 的那一个质因子。
时间复杂度是 n \sqrt{n} n。(最好是 log n \log{n} logn)
868. 筛质数
关于筛质数的详细总结可见:【算法】数学相关知识总结
埃氏筛
从小到大进行枚举,每次枚举到一个质数,就把数据范围内它的所有倍数都删掉。
import java.util.*;
public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
boolean[] f = new boolean[n + 1];
Arrays.fill(f, true);
int cnt = 0;
for (int i = 2; i <= n; ++i) {
if (f[i]) {
++cnt;
for (int j = 2; i <= n / j; ++j) {
f[i * j] = false;
}
}
}
System.out.println(cnt);
}
}
欧氏筛 / 线性筛
n只会被它的最小质因子筛掉
每次循环 j 是为了筛掉所有已经发现的质数的 i 倍,即 prime[j] 的意义是目前已经发现的第 j 个质数。
import java.util.*;
public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(), cnt = 0;
int[] prime = new int[n + 1], st = new int[n + 1];
for (int i = 2; i <= n; ++i) {
if (st[i] == 0) prime[cnt++] = i;
for (int j = 0; prime[j] <= n / i; ++j) {
st[prime[j] * i] = 1;
if (i % prime[j] == 0) break;
}
}
System.out.println(cnt);
}
}
相关链接
【算法】数学相关知识总结