史密斯数是合数,且其各位数字之和等于所有质因数(含重复)的各位数字之和;例如27=3×3×3,数字和均为9,故为史密斯数。

什么是史密斯数?先看判定逻辑
史密斯数不是质数,但它的各位数字之和等于它所有质因数(含重复)的各位数字之和。比如 27:
- 数字和是
2 + 7 = 9 - 质因数分解为
3 × 3 × 3,质因数数字和是3 + 3 + 3 = 9 - 它不是质数(
27可被3整除),所以27是史密斯数
关键点有三个:
- 必须是合数(即非质数且 > 1)
- 各位数字之和要等于其质因数(每个都拆开算各位)的数字和
- 质因数要按重数展开,比如
4 = 2 × 2,就得算两个2,不能只算一次
怎么写一个靠谱的 isSmith(int n) 函数
直接上核心逻辑,不绕弯:
- 先排除
n <= 1、质数、以及个位数(2~9都不是史密斯数,因为它们全是质数或1) - 写一个辅助函数
digitSum(int x),返回 x 的各位数字和(对x % 10循环取余即可) - 写一个质因数分解循环:从
i = 2开始试除,每次把i的所有因子除尽,并把i加入质因数列表(或直接累加它的digitSum(i)) - 注意:如果最后剩下一个 > 1 的数(比如
n = 25除完5后剩5),它本身也是质因数,要计入
常见错误:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
立即学习“C++免费学习笔记(深入)”;
- 忘记判断是否为质数,直接对质数算——结果会误判(如
13数字和是4,质因数只有13,数字和也是4,但它不是合数,不能算史密斯数) - 质因数分解时没处理剩余大质数(比如
97这种,试到sqrt(n)就停,漏掉它自己) - 把
digitSum写成只处理正数,但输入保证是正整数,这点倒不用额外检查
一个轻量、可验证的实现示例int digitSum(int x) {
int s = 0;
while (x) {
s += x % 10;
x /= 10;
}
return s;
}
<p>bool isPrime(int n) {
if (n < 2) return false;
if (n == 2) return true;
if (n % 2 == 0) return false;
for (int i = 3; i * i <= n; i += 2)
if (n % i == 0) return false;
return true;
}</p><p>bool isSmith(int n) {
if (n < 4 || isPrime(n)) return false; // 最小合数是 4,质数直接否
int sumDigits = digitSum(n);
int sumFactors = 0;
int temp = n;
for (int i = 2; i * i <= temp; ++i) {
while (temp % i == 0) {
sumFactors += digitSum(i);
temp /= i;
}
}
if (temp > 1) sumFactors += digitSum(temp); // 剩余大质数
return sumDigits == sumFactors;
}
注意几个边界:
-
isSmith(4)→digitSum(4)=4,质因数是2×2,digitSum(2)+digitSum(2)=4,返回true -
isSmith(1)、isSmith(2)、isSmith(3)都返回false -
isSmith(378)是经典例子(2×3×3×3×7,数字和3+7+8=18,质因数数字和2+3+3+3+7=18)
性能与可扩展性提醒
这个实现对 n ≤ 10⁶ 没问题,但若频繁调用或 n 达到 10⁹ 级别,要注意:
-
isPrime在isSmith里其实冗余了——我们已经在分解质因数,完全可以通过“是否只被自己整除过一次”来间接判断是否为质数,但为清晰起见,单独写更易 debug -
digitSum可以用查表法加速(最多 10 位,预存 0~9999 的数字和),但对单次判断意义不大 - 如果批量判断,建议预筛出质数表(如埃氏筛),再复用质因数分解逻辑,避免重复计算
最常被忽略的一点:史密斯数定义明确要求“合数”,而很多人只比数字和,忘了先过 isPrime 这关。哪怕数字和相等,只要 n 是质数,就不是史密斯数。

















