Medium
题目描述
给定一个整数 n。
返回小于或等于 n 的最大质数,该质数可以表示为从 2 开始的一个或多个连续质数的和。如果不存在这样的数,返回 0。
示例 1:
输入:n = 20
输出:17
解释:
小于或等于 n = 20 的质数中,可以表示为连续质数和的有:
2 = 2
5 = 2 + 3
17 = 2 + 3 + 5 + 7
最大的是 17,所以答案是 17。
示例 2:
输入:n = 2
输出:2
解释:
小于或等于 2 的唯一连续质数和是 2 本身。
约束条件:
1 <= n <= 5 * 10^5
提示:
- 生成所有小于等于 n 的质数(使用埃拉托斯特尼筛法或试除法)
- 计算从 2 开始的连续和,直到和超过 n
- 找到既是质数又是连续质数和的最大值
解题思路
解题思路
这是一道综合性的数论题,需要结合质数生成和前缀和计算。
核心思路:
- 生成质数:使用埃拉托斯特尼筛法生成所有小于等于 n 的质数
- 计算连续和:从质数 2 开始,计算所有可能的连续质数和
- 记录有效和:将所有小于等于 n 且为质数的连续和记录下来
- 返回最大值:从所有有效的连续质数和中返回最大值
具体步骤:
- 使用筛法生成质数列表和质数判断数组
- 对于每个起始位置,累加连续质数直到和超过 n
- 在累加过程中,如果当前和是质数且小于等于 n,则更新答案
- 由于我们要找最大值,从大到小遍历或者维护最大值即可
优化点:
- 使用埃拉托斯特尼筛法预处理,时间复杂度 O(n log log n)
- 连续和的计算是 O(质数个数²),实际上质数密度不高,效率可接受
- 可以用前缀和优化,但由于要枚举所有起始位置,时间复杂度本质相同
代码实现
class Solution {
public:
int largestPrime(int n) {
// 埃拉托斯特尼筛法生成质数
vector<bool> isPrime(n + 1, true);
vector<int> primes;
isPrime[0] = isPrime[1] = false;
for (int i = 2; i <= n; i++) {
if (isPrime[i]) {
primes.push_back(i);
for (long long j = (long long)i * i; j <= n; j += i) {
isPrime[j] = false;
}
}
}
int result = 0;
// 枚举所有可能的连续质数和
for (int i = 0; i < primes.size(); i++) {
int sum = 0;
for (int j = i; j < primes.size(); j++) {
sum += primes[j];
if (sum > n) break;
if (isPrime[sum]) {
result = max(result, sum);
}
}
}
return result;
}
};
class Solution:
def largestPrime(self, n: int) -> int:
# 埃拉托斯特尼筛法生成质数
is_prime = [True] * (n + 1)
is_prime[0] = is_prime[1] = False
primes = []
for i in range(2, n + 1):
if is_prime[i]:
primes.append(i)
for j in range(i * i, n + 1, i):
is_prime[j] = False
result = 0
# 枚举所有可能的连续质数和
for i in range(len(primes)):
sum_val = 0
for j in range(i, len(primes)):
sum_val += primes[j]
if sum_val > n:
break
if is_prime[sum_val]:
result = max(result, sum_val)
return result
public class Solution {
public int LargestPrime(int n) {
// 埃拉托斯特尼筛法生成质数
bool[] isPrime = new bool[n + 1];
Array.Fill(isPrime, true);
isPrime[0] = isPrime[1] = false;
List<int> primes = new List<int>();
for (int i = 2; i <= n; i++) {
if (isPrime[i]) {
primes.Add(i);
for (long j = (long)i * i; j <= n; j += i) {
isPrime[j] = false;
}
}
}
int result = 0;
// 枚举所有可能的连续质数和
for (int i = 0; i < primes.Count; i++) {
int sum = 0;
for (int j = i; j < primes.Count; j++) {
sum += primes[j];
if (sum > n) break;
if (isPrime[sum]) {
result = Math.Max(result, sum);
}
}
}
return result;
}
}
var largestPrime = function(n) {
// 埃拉托斯特尼筛法生成质数
const isPrime = new Array(n + 1).fill(true);
isPrime[0] = isPrime[1] = false;
const primes = [];
for (let i = 2; i <= n; i++) {
if (isPrime[i]) {
primes.push(i);
for (let j = i * i; j <= n; j += i) {
isPrime[j] = false;
}
}
}
let result = 0;
// 枚举所有可能的连续质数和
for (let i = 0; i < primes.length; i++) {
let sum = 0;
for (let j = i; j < primes.length; j++) {
sum += primes[j];
if (sum > n) break;
if (isPrime[sum]) {
result = Math.max(result, sum);
}
}
}
return result;
};
复杂度分析
| 复杂度类型 | 分析 |
|---|---|
| 时间复杂度 | O(n log log n + p²),其中 p 是小于等于 n 的质数个数。筛法需要 O(n log log n),枚举连续和需要 O(p²) |
| 空间复杂度 | O(n + p),需要 O(n) 空间存储筛法数组,O(p) 空间存储质数列表 |