【算法学习】素数筛和线性筛问题

素数筛和线性筛问题

  • 1.原理分析(素数筛和线性筛)
  • 2.关于素数问题
    • a.标记0-500里面的素数
    • b.欧拉7题
      • 1)基础版代码(普通素数方法)
      • 2)进阶版代码(素数筛方法)
      • 3)进进阶版代码(线性筛方法)
  • 3.扩展问题
    • a.快速写出2-10000每个数对应的最小素因子
    • b.快速写出2-10000每个数对应的最大素因子

1.原理分析(素数筛和线性筛)

【算法学习】素数筛和线性筛问题_第1张图片【算法学习】素数筛和线性筛问题_第2张图片

2.关于素数问题

a.标记0-500里面的素数

代码如下:

#include
#define max_n 500

int arr[max_n + 5] = {
     1, 1};
void prime(){
     
    for(int i = 2; i * i <= max_n; i++){
     
        if(arr[i]) continue;//对偶逻辑减少缩进
        for(int j = i * i; j < max_n; j += i){
     //从i * i开始  i * (i - 1)已经被(i-1)或其素因子标记过了
            arr[j] = 1;
        }
    }
}

int main(){
     
    int n;
    prime();
    while(~scanf("%d", &n)){
     
        if(arr[n]) printf("%d is not prime\n", n);
        else printf("%d is prime\n", n);
    }
    return 0;

}

运行结果
【算法学习】素数筛和线性筛问题_第3张图片

b.欧拉7题

题目描述

第10001个素数
列出前6个素数,它们分别是2、3、5、7、11和13。我们可以看出,第6个素数是13。
第10,001个素数是多少?

1)基础版代码(普通素数方法)

#include
int is_val(int n){
     
    for(int i = 2; i * i <= n; i++){
     
        if(n % i == 0) return 0;
    }
    return 1;
}
int main(){
     
    int i, cnt;
    for(i = 2, cnt = 0; cnt < 10001; i++){
     
        if(is_val(i)) cnt += 1;
    }
    printf("%d\n", i - 1);
    return 0;
}

2)进阶版代码(素数筛方法)

#include
#include
#define max_n 200000//素数符合一个规则 即要找第n个素数 这个素数一定在20*n的范围中

int arr[max_n + 5] = {
     0};

void prime(){
     
    for(int64_t i = 2; i <= max_n; i++){
     //i的上限为max_n而不是sqrt(max_n),如果用后者,则所有的素数全部找出了,但是并没有将第100往后的素数遍历到,也就是100以后的素数未存入数组的对应位置
        if(arr[i]) continue;//当继续往下执行时,则说明i是素数
        //arr[++arr[0]] = i;
        ++arr[0];
        arr[arr[0]] = i;//arr[0]记录素数个数,将第i个素数赋值给arr[i],因为当循环到i时,前i个数已经判断完毕,所以可以使用arr[i]
        for(int64_t j = i * i; j <= max_n; j += i){
     //j = i * i i最大为200000,所以j需用64位,如果i用int,则在运算时200000*200000时就会爆掉
            arr[j] = 1;
        }
    }
}

int main(){
     
    prime();
    printf("%d is the 10001st prime number\n", arr[10001]);
    return 0;
}

在这里插入图片描述

3)进进阶版代码(线性筛方法)

#include
#define max_n 200000

int prime[max_n + 5] = {
     0};

void init(){
     
    for(int i = 2; i < max_n; i++){
     //i的上界为max_n/2时,素数全部标记,但没更新到对应的数组中
        if(!prime[i]) prime[++prime[0]] = i;//如果是素数,则更新素数表
        for(int j = 1; j <= prime[0]; j++){
     //j不能从0开始 prime[0]存放的素数个数
            if(i * prime[j] > max_n) break;
            prime[i * prime[j]] = 1;
            if(i % prime[j] == 0) break;//当此时的i对素数表中的素数取模为0时停止标记
        }
    }
}

int main(){
     

    init();
    printf("%d is the 10001st prime number\n", prime[10001]);
    
    return 0;
}


在这里插入图片描述

3.扩展问题

记住素数筛和线性筛是一类框架,不仅仅是算法,可以用其解决相似的问题

a.快速写出2-10000每个数对应的最小素因子

#include
#define max_n 10000

int arr[max_n + 5] = {
     0};

void prime(){
     
    for(int i = 2; i <= max_n; i++){
     //i的上界为max_n,如果是sqrt,则当i>100时,素数对应的数组里面是0
        if(arr[i]) continue;
        for(int j = i; j <= max_n; j += i){
     //j从i开始,如果j从i*i开始,则遍历不到当前的素数i,此时对应的arr[i]=0
            if(arr[j]) continue;//如果已经用素数标记过,则不再更新值,前面的素数肯定更小
            arr[j] = i;
        }
    }
    return ;
}

int main(){
     
    prime();
    int n;
    while(~scanf("%d", &n)){
     
        printf("min prime yinzi is %d\n", arr[n]);
    }
    return 0;
}

【算法学习】素数筛和线性筛问题_第4张图片

b.快速写出2-10000每个数对应的最大素因子

#include
#define max_n 10000

int arr[max_n + 5] = {
     0};

void prime(){
     
    for(int i = 2; i <= max_n; i++){
     //i的上界为max_n,如果是sqrt,则当i>100时,素数对应的数组里面是0
        if(arr[i]) continue;
        for(int j = i; j <= max_n; j += i){
     //j从i开始,如果j从i*i开始,则遍历不到当前的素数i,此时对应的arr[i]=0
            //if(arr[j]) continue;//如果已经用素数标记过,则不再更新值,前面的素数肯定更小
            arr[j] = i;
        }
    }
    return ;
}

int main(){
     
    prime();
    int n;
    while(~scanf("%d", &n)){
     
        printf("min prime yinzi is %d\n", arr[n]);
    }
    return 0;
}

【算法学习】素数筛和线性筛问题_第5张图片

你可能感兴趣的:(算法学习,c语言,算法,面试)