史密斯数必须是合数且各位数字和等于其质因数各位数字之和;函数需先判断合数(排除1和质数),再分解质因数并展开重复因子求数字和,注意digitsum处理非负整数。

不是所有数字和相等的合数都是史密斯数,但所有史密斯数必须是合数且满足数字和相等——漏掉「合数判断」就直接误判质数(比如13、17)。
isSmithNumber() 必须先做合数判断
史密斯数定义明确排除质数和1,所以函数开头不能只写 if (n 就完事。这个条件能拦住1、2、3,但对5、7、11等质数无效。
- 正确做法:先用
is_composite(n)或内联逻辑判断是否为合数——即 n > 1 且存在某个 i ∈ [2, √n] 满足n % i == 0 - 别复用
is_prime()取反,容易把1当成合数(1既非质也非合) - 小值特判可简化:
if (n ,然后直接试除到 <code>sqrt(n),若没找到因子且 n > 1,说明是质数 → 返回 false
质因数分解时要展开重复因子并累加 digitSum
比如 8 = 2 × 2 × 2,得调用三次 digitSum(2),而不是只算一次;又如 9 = 3 × 3,也要加两次 digitSum(3)。常见错误是把因子集合当成了因子列表。
- 循环从
i = 2开始,条件写成i * i ,避免浮点 <code>sqrt()带来的精度问题 - 每进入一次
while (temp % i == 0),就执行sumPrimeDigits += digitSum(i); temp /= i; - 循环结束后若
temp > 1,说明剩下一个未被试除到的大质因数,必须再加一次digitSum(temp) - 别用
std::vector存因子——没必要,还多一次遍历
digitSum() 要处理 0 和避免负数陷阱
digitSum(-27) 在某些编译器下 -27 % 10 是 -7,导致结果错误。史密斯数只定义在正整数上,但函数健壮性要求输入非负。
- 统一用
int digitSum(int x) { x = x -
digitSum(0)必须返回 0 ——虽然史密斯数不包含 0,但防止后续逻辑传入异常值 - 不要用
std::to_string:开销大、依赖 locale、且对 0 的处理不如取模直观
int 溢出风险:i * i
当 temp 接近 INT_MAX(约 2.1e9)时,i 到 46340 左右,i * i 就会溢出成负数,导致循环失控。
- 安全写法:改用
i ,整除无溢出 - 或升为
long long i,但注意temp仍是int,需同步转类型 - 如果输入可能达 10⁹ 级别,建议整个函数参数用
long long,并把循环变量也声明为long long - 别信「我只测小数」——线上环境输入不可控,边界不稳等于逻辑不稳
最常被跳过的其实是「合数判定」和「残留大质因数」这两步,它们不出现在样例 4、22、27 里,却在 58(=2×29)、121(=11×11)这类数上暴露问题。写完先拿 13、17、97 这些质数过一遍,再试 1、0、负数,基本就能避开 80% 的坑。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











