质数定义:在大于1的整数中,如果只包含1和本身这两个约数,就被成为质数,或者叫素数。
质数的判定——试除法
从1到n循环判断是否能被整除,如果能被整除说明n不是质数,不能被整除说明是质数。
因为每个除数都是成对出现的,比如
12
=
2
×
6
12=2 \times 6
12=2×6,
12
=
3
×
4
12=3 \times 4
12=3×4,2和4对应,3和6对应,分别是一个大于
12
\sqrt{12}
12,一个小于
12
\sqrt{12}
12,12能够被2整除那么一定也可以被6整除,所以可以让循环判断的范围从1到n缩小到1到
n
\sqrt{n}
n
试除法的时间复杂度是
O
(
s
q
r
t
(
n
)
)
O(sqrt(n))
O(sqrt(n))
import java.io.*;
public class Main{
public static void main(String[] args)throws IOException{
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
int n=Integer.parseInt(in.readLine());
for(int i=0;i<n;i++){
int a=Integer.parseInt(in.readLine());
boolean flag=scf(a);
if(flag)System.out.println("Yes");
else System.out.println("No");
}
}
static boolean scf(int n){
if(n<2)return false;
for(int i=2;i<=n/i;i++){
if(n%i==0)return false;
}
return true;
}
}
分解质因数——试除法
利用试除法从1到n遍历,计算相应质因数的个数,因为循环是从小到大遍历的缘故,所以不会存在质因数是合数的情况。比如循环遍历到4时,不会计算4这个不是质数的因素,因为n中的2已经被除完了。
因为n只存在一个大于
n
\sqrt{n}
n的质因数,所以,循环可以从1到n缩减到1到
n
\sqrt{n}
n,然后在循环外特判以下就好了。比如
110
=
2
×
5
×
11
110=2 \times 5 \times 11
110=2×5×11,如果
11
×
11
=
121
11 \times 11=121
11×11=121就超出110的范围了。
import java.io.*;
public class Main{
public static void main(String[] args)throws IOException{
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
int n=Integer.parseInt(in.readLine());
for(int i=0;i<n;i++){
int a=Integer.parseInt(in.readLine());
scf(a);
System.out.println();
}
}
static void scf(int n){
for(int i=2;i<=n/i;i++){
if(n%i==0){
int s=0;
while(n%i==0){
n/=i;
s++;
}
System.out.println(i+" "+s);
}
}
if(n>1)System.out.println(n+" "+1);
}
}
筛法求质数
普通筛法
如上图所示:
从左到右筛除相应非质数。
import java.io.*;
public class Main{
static int N=1000010;
static boolean[] st=new boolean[N];
static int[] primes=new int[N];
static int cnt;
public static void main(String[] args)throws IOException{
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
int n=Integer.parseInt(in.readLine());
assf(n);
}
static void assf(int n){
for(int i=2;i<=n;i++){
if(!st[i])primes[cnt++]=i;
for(int j=i+i;j<=n;j+=i)
st[j]=true;
}
System.out.println(cnt);
}
}
埃式筛法
如上图所示:
当为质数时才进行后续的相应筛除
import java.io.*;
public class Main{
static int N=1000010;
static boolean[] st=new boolean[N];
static int[] primes=new int[N];
static int cnt;
public static void main(String[] args)throws IOException{
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
int n=Integer.parseInt(in.readLine());
assf(n);
}
static void assf(int n){
for(int i=2;i<=n;i++){
if(!st[i]){
primes[cnt++]=i;
for(int j=i+i;j<=n;j+=i)
st[j]=true;
}
}
System.out.println(cnt);
}
}
线性筛法
每次都是用被筛除掉的数的最小质因子将其筛除的
①
i
i
i %
p
j
=
=
0
:
p_j==0:
pj==0:因为
i
,
j
i,j
i,j是从小到大枚举的,所以
p
j
p_j
pj一定是
i
i
i的最小质因子,
p
j
p_j
pj一定是
p
j
×
i
p_j \times i
pj×i的最小质因子
②
i
i
i %
p
j
!
=
0
:
p
j
p_j!=0:p_j
pj!=0:pj一定小于
i
i
i的所有质因子,
p
j
p_j
pj也一定是
p
j
×
i
p_j \times i
pj×i的最小质因子
import java.io.*;
public class Main{
static int N=1000010;
static boolean[] st=new boolean[N];
static int[] primes=new int[N];
static int cnt;
public static void main(String[] args)throws IOException{
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
int n=Integer.parseInt(in.readLine());
xxsf(n);
}
static void xxsf(int n){
for(int i=2;i<=n;i++){
if(!st[i]) primes[cnt++]=i;
for(int j=0;primes[j]<=n/i;j++){
st[primes[j]*i]=true;
if(i%primes[j]==0)break;
}
}
System.out.println(cnt);
}
}