强素数是数论中定义的素数p_n,满足p_n > (p_{n-1} + p_{n+1})/2,即严格大于其前后相邻素数的平均值;需预筛素数表并用二分查找定位索引,再验证边界与不等式。

什么是强素数?先看定义再写代码
强素数不是标准库函数或语言内置概念,而是数论里的一个定义:一个素数 p 是强素数,当且仅当它严格大于其前后两个相邻素数的平均值。即:若 p_n 是第 n 个素数,则 p_n > (p_{n-1} + p_{n+1}) / 2。注意,最小的几个素数(如 2、3、5)没有前驱或后继,因此通常从第 3 个素数(即 5)开始判断。
这意味着你不能只判断单个数是否为素数,还必须知道它在素数序列中的位置,以及它的前一个和后一个素数——所以「判断强素数」本质上是个**上下文依赖操作**,不是单个整数的独立属性。
如何获取前驱/后继素数?别硬算,用预生成+二分
暴力对每个查询都向前向后试除找邻近素数,效率极低,尤其当输入可能达 10⁵ 或更高时。更实用的做法是预先筛出足够范围内的素数(比如用埃氏筛到 10⁶),存进 std::vector<int></int>,再用 std::lower_bound 定位目标值。
- 若
lower_bound找到的是vec.begin()或vec.end(),说明该数不在素数表中,直接返回false - 若找到索引
i,需检查vec[i] == target(避免把合数误判为素数) - 确认是素数后,检查
i > 0 && i + 1 ,否则无前驱或后继,按定义不构成强素数 - 然后计算:
vec[i] * 2 > vec[i-1] + vec[i+1](用乘法避免浮点和整数除法截断问题)
C++ 实现的关键细节和易错点
常见错误不是逻辑写错,而是边界处理漏掉:
-
is_prime(n)函数如果只用于预筛,就别重复实现;筛完直接查表更快更安全 - 强素数定义中「严格大于」,所以用
>,不是>=;例如 11 是素数,前驱 7、后继 13,(7+13)/2 = 10 → 11 > 10,成立 - 输入为负数、0、1 时,
lower_bound可能越界,必须先排除非正整数 - 筛表大小要覆盖可能的「后继素数」——比如你要判断 997,就得筛到至少 1009(下一个素数),建议上限设为
max_input * 2或固定 1.5×10⁶
示例片段(简化版):
std::vector<int> primes = sieve(1200); // 确保含 997 和 1009 int x = 11; auto it = std::lower_bound(primes.begin(), primes.end(), x); if (it == primes.end() || *it != x) return false; int i = it - primes.begin(); if (i == 0 || i == (int)primes.size()-1) return false; return primes[i] * 2 > primes[i-1] + primes[i+1]; </int>
强素数在实际工程中几乎不用,但面试题常考陷阱
注意:密码学里有时也叫「strong prime」,但定义不同(要求 p−1 和 p+1 有大素因子等),和数论定义冲突。如果题目没明确上下文,务必确认定义来源——竞赛题一般用数论定义,密码学文献则用另一套。
另外,std::lower_bound 返回的是第一个 ≥ x 的迭代器,必须显式比对 *it == x,否则会把合数当成素数(比如查 25,在素数表 {2,3,5,7,11,…} 中找到 29,误认为 25 是第某位素数)。
真正麻烦的不是代码,是定义模糊时要不要支持 2、3 这类边界素数——多数资料明确排除它们,因为缺少前驱或后继,这点容易被忽略。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











