质数定义:在大于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);
}
}