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;
}
};