半素数是质因数分解后素因子指数和恰好为2的正整数(如4=2×2、6=2×3);不能只试除到√n后简单判断,必须统计所有素因子(含剩余大于√n的素因子)的总个数,仅当总数严格等于2时才成立。

什么是半素数,以及为什么不能只试除到√n
半素数是指恰好由两个素数相乘得到的正整数(允许相同,如 4 = 2×2、6 = 2×3、9 = 3×3),且不能有其他素因子。关键点在于:它必须**恰好有两个素因子(计重)**,即质因数分解后总指数和为 2。
常见错误是写个循环从 2 试除到 sqrt(n),找到一个因子就返回 true —— 这会把 12(= 2×2×3)误判为半素数。它有三个素因子(计重),不是半素数。
正确思路是:完全分解 n,统计所有素因子的指数之和。只有当这个和严格等于 2 时,才是半素数。
如何高效完成质因数分解并计数
对正整数 n 做试除时,只需枚举到 sqrt(n),但必须处理剩余的大于 sqrt(n) 的那个可能素因子(即“余数”)。这个余数要么是 1,要么是素数(因为所有 ≤ √n 的因子都已被除尽)。
立即学习“C++免费学习笔记(深入)”;
- 用变量
count累加每个素因子的出现次数(不是不同素因子个数) - 从小到大试除
i从 2 开始,只要i * i 就循环 - 每次整除时,
count++,并持续除尽该因子(避免重复计数同一因子多次) - 循环结束后,若
n > 1,说明剩下一个素因子,count++ - 最终判断
count == 2
示例:n = 15 → 试除 i=3 得 15/3=5,count=1;i=4 不整除;i=5 时 i*i=25 > 5,退出循环;此时 n=5 > 1,count 变为 2 → 是半素数。
C++ 实现要点与易错细节
注意整型溢出和边界情况:
-
n == 1直接返回 false(1 没有素因子) - 循环中用
i * i 而非 <code>i ,避免浮点误差和类型转换开销 -
i必须声明为int或long long,取决于n范围;若n可达 10⁹,i用int足够(√10⁹ ≈ 31622) - 内层 while 除尽时,要确保
n % i == 0才进循环,否则跳过 - 不要提前 return true;必须完成全部分解再判断
count
简短实现示意:
bool isSemiprime(int n) {
if (n < 4) return false; // 最小半素数是 4
int count = 0;
for (int i = 2; i * i <= n; i++) {
while (n % i == 0) {
count++;
n /= i;
}
}
if (n > 1) count++;
return count == 2;
}
性能与特殊值验证建议
这个算法平均复杂度约 O(√n),对 10⁹ 内的数足够快。但要注意几个典型反例:
-
isSemiprime(4)→ true(2×2) -
isSemiprime(6)→ true(2×3) -
isSemiprime(8)→ false(2×2×2,count=3) -
isSemiprime(17)→ false(素数,count=1) -
isSemiprime(30)→ false(2×3×5,count=3)
最容易被忽略的是:半素数定义不关心因子是否相同,只看素因子总数(含重复)是否为 2 —— 这直接决定你是否在 while 循环里正确累加 count,而不是只记录不同因子个数。


















