史密斯数是非质数的正整数,其各位数字之和等于所有质因数(含重复)的各位数字之和;例如22不是质数,数字和为4,质因数2×11的数字和2+1+1也为4,故是史密斯数。

什么是史密斯数?先看判定逻辑
史密斯数不是质数,但它的各位数字之和等于它所有质因数(含重复)的各位数字之和。比如 22:它本身不是质数,各位和是 2 + 2 = 4;质因数分解为 2 × 11,质因数各位和是 2 + 1 + 1 = 4,相等 → 是史密斯数。
关键点有三个:非质数、能分解出质因数、数字和必须严格相等。别漏掉“非质数”这个前提——质数永远不算史密斯数,哪怕数字和碰巧一样。
怎么快速算一个数的各位数字和?
用循环取余就行,不依赖字符串转换,避免分配内存或类型转换开销:
int digitSum(int n) {
int s = 0;
while (n) {
s += n % 10;
n /= 10;
}
return s;
}
注意:n 为 0 时这个函数返回 0,但史密斯数定义中最小的是 4(22 是第一个常见例子),所以实际调用前可加 n > 0 判断。别传负数——史密斯数只定义在正整数上。
质因数分解时最容易错在哪?
常见错误是只试到 sqrt(n) 就停,却忘了最后剩下一个大于 sqrt(n) 的质因数(比如 22 分解完 2 后剩 11,而 sqrt(22) ≈ 4.6,11 没被扫到)。
- 循环因子从
2开始,一直试到i * i - 每次整除就累加该因子的各位和(比如
8 = 2×2×2,要加三次digitSum(2)) - 循环结束后若
n > 1,说明剩下一个质因数,也要加一次digitSum(n)
别用筛法预处理——单次判断没必要;也别用递归分解,容易栈溢出或重复计算。
完整判断函数怎么写才可靠?
把上面几块拼起来,重点控制边界:
bool isSmith(int n) {
if (n int sumDigits = digitSum(n);
int sumFactors = 0;
int temp = n;
for (int i = 2; i * i 1) sumFactors += digitSum(temp);
return sumDigits == sumFactors;
}
isPrime() 自己写就行,试除到 sqrt(n) 即可。注意 n=4 这种小数:它合数、各位和 4,质因数只有 2×2,各位和也是 2+2=4 → 是史密斯数。很多人误以为史密斯数都很大,其实 4 就是第一个。
真正容易被忽略的是:当 n 是某个质数的高次幂(如 125 = 5³),必须把每个 5 都单独计入数字和,不能只算一次 digitSum(5) 再乘 3 —— 虽然结果一样,但逻辑上必须体现“每个质因数”的各位和,否则遇到像 100 = 2²×5² 这种(2+2+5+5=14)就容易错。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











