LeetCode/和等于目标值的质数对

给你一个整数n,如果两个整数 x 和 y 满足下述条件,则认为二者形成一个质数对:

  • 1 <= x <= y <= n
  • x + y == n
  • x 和 y 都是质数

请你以二维有序列表的形式返回符合题目要求的所有[xi, yi],列表需要按 xi 的非递减顺序排序。如果不存在符合要求的质数对,则返回一个空数组。

1. 埃氏筛预处理

把素数的倍数记为合数,从前往后的情况下
没有被标记的便是素数(即不存在更小的因数)

vector<bool> prime(10e6,true);
bool flag = false;

void getprime(){//埃氏筛预处理
    for(int i=2;i<10e6;i++){
        if(prime[i]==false) continue;
        for(int j=2*i;j<10e6;j=j+i)
            prime[j] = false;
    }
    flag = true;
}

class Solution {
public:
    //可以预处理先把质数筛出来
    vector<vector<int>> findPrimePairs(int n) {
        if(!flag) getprime();
        vector<vector<int>> res;
        for(int i=2;i<=n/2;i++)
            if(prime[i]&&prime[n-i]) res.push_back({i,n-i});
        return res;
    }
};

2. 线性筛

通过固定枚举顺序,减少埃氏筛中的重复筛选
即枚举所有数和所有更小质数的乘积为非素数
但合数与质数的乘积只枚举到该合数的最小质因数,因为之后的乘积会在后面重复枚举,表示为更大的合数和该质因数之积

vector<bool> prime(10e6,true);
vector<int> nums(10e5);//记录所有质数
int cnt = 0;
bool flag = false;

void getprime(){//欧拉筛预处理,关键在于,合数只和比自己质因数更小的质数结合
    for(int i=2;i<10e6;i++){
        if(prime[i]) nums[cnt++] = i;//从前往后记录素数
        for(int j=0;j<cnt && i*nums[j]<10e6;j++){ //枚举所有素数
            prime[i*nums[j]] = false; //素数和素数的乘积,以及合数和素数的乘积,皆为合数
            if(i%nums[j]==0) break; //如果i为素数,会一直枚举, 如果i为合数,枚举到存在它的质数因数,
            //合数与比自己质因数更大的质数乘积时,可以表示为,更小的素数与更大的合数的乘积,所以后面会遍历到,这里避免重复筛选
        }
    } 
    flag = true;
}

class Solution {
public:
    //可以预处理先把质数筛出来
    vector<vector<int>> findPrimePairs(int n) {
        if(!flag) getprime();
        vector<vector<int>> res;
        for(int i=2;i<=n/2;i++)
            if(prime[i]&&prime[n-i]) res.push_back({i,n-i});
        return res;
    }
};
posted @ 2023-07-02 16:26  失控D大白兔  阅读(17)  评论(0编辑  收藏  举报