卡普列加数指非负整数n,其平方可从某位中间切开成两部分(右部非空),两部分之和恰为n;不能直接用pow()因浮点误差易致大数拆分错误,应改用字符串或整型幂运算。

什么是卡普列加数,以及为什么不能直接用 pow() 拆分
一个正整数 n 是卡普列加数(Kaprekar number),当且仅当它的平方 n * n 可以被**从某一位中间切开**(非末尾、非开头,但允许左/右部分为 0)成两个正整数(或一个为 0,另一个等于 n),使得它们的和等于 n。例如:9 是卡普列加数,因为 9*9=81,拆成 8 + 1 = 9;45 也是,因为 45*45=2025,可拆为 20 + 25 = 45。
关键陷阱在于:不能简单按“位数一半”切——比如 297 的平方是 88209(5 位),必须尝试所有合法切点(即从第 1 位后到倒数第 1 位前),且右边部分长度不能为 0(否则就是整个数,左边为 0,不满足定义)。更麻烦的是:pow(10, k) 在整数运算中易因浮点误差出错,尤其对大数(如 n > 1e9);应改用字符串或迭代乘 10。
如何安全地枚举所有合法切分位置
对 n * n 的十进制表示(记作 s),长度为 len,合法切点在索引 i 处(1 ≤ i len),即左段为 s.substr(0, i),右段为 s.substr(i)。但要注意:
- 右段不能全为 '0'(即数值为 0 是允许的,但字符串不能是 "000" 这种——不过标准定义中,右段为 0 是允许的,只要左段等于
n;实际实现中,我们只关心数值,所以直接转整数即可) - 左段为空或右段为空都不合法(对应
i == 0或i == len),所以循环范围是i = 1到len - 1 - 用字符串切分最直观,避免溢出和浮点误差;若坚持用数值法,可用
divisor = 10循环更新,每次left = sq / divisor,right = sq % divisor,然后divisor *= 10
C++ 实现时容易忽略的边界情况
以下情况必须单独处理,否则会漏判或误判:
-
n == 1:1*1 = 1,按定义可视为 "" + "1" 或 "1" + "",但标准定义接受它为卡普列加数;需显式返回true - 右段以 '0' 开头(如
100→ 平方为10000,切为 "100" + "00" → 右段数值是 0,合法;但字符串转整数自动去前导零,所以没问题) - 左段为 "0"(如
n = 10,平方 = 100,切为 "1" + "00" → 1 + 0 = 1 ≠ 10;切为 "10" + "0" → 10 + 0 = 10 → 成立,所以10是卡普列加数) - 使用
stoll()而非stoi(),防止n较大时平方溢出int(n最大可到1e5,平方达1e10,需long long)
一个简洁可靠的判断函数
下面是一个生产可用的 isKaprekar() 函数,兼顾可读性与边界安全:
bool isKaprekar(long long n) {
if (n == 1) return true;
long long sq = n * n;
string s = to_string(sq);
int len = s.length();
for (int i = 1; i <p>注意:<code>stoll</code> 在输入为空串时会抛异常,但循环中 <code>right_str</code> 非空,<code>left_str</code> 也非空(因 <code>i ≥ 1</code>),所以安全。真正容易被忽略的是:卡普列加数定义中,**右段可以为 0,但左段不能为 0(除非 n==1)** —— 上述代码没显式排除 left==0,是因为当 left==0 时,right==sq,而 sq > n(n>1 时),所以 left+right == sq > n,自然不成立,无需额外判断。</p>C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











