三角形数是形如k(k+1)/2(k为正整数)的正整数,如1、3、6、10、15;判定时需验证判别式1+8n是否为完全平方数且其平方根为奇数,再通过整数校验避免浮点误差。

什么是三角形数?先看代数判定公式
一个正整数 n 是三角形数,当且仅当存在某个正整数 k,使得 n = k * (k + 1) / 2。把这个式子变形:解关于 k 的二次方程 k² + k − 2n = 0,判别式为 Δ = 1 + 8 * n。所以只需判断 sqrt(1 + 8 * n) 是否为整数,且该整数减 1 后能被 2 整除。
实操时要注意浮点精度问题:直接用 sqrt 返回 double,再转 long long 可能出错。稳妥做法是计算 root = round(sqrt(1 + 8.0 * n)),再验证 root * root == 1 + 8 * n 且 (root - 1) % 2 == 0。
- 推荐写法:
long long disc = 1 + 8LL * n;(防int溢出) - 避免写
sqrt(1 + 8 * n)—— 若n较大,8 * n可能溢出int -
round()比floor()或强制截断更安全,尤其对接近整数的浮点结果
迭代法怎么写?边界和提前退出很关键
迭代就是从 k = 1 开始试,算 k * (k + 1) / 2,直到结果 ≥ n。看起来简单,但容易忽略两个坑:一是 k * (k + 1) 在循环中可能溢出;二是没及时 break 导致无谓循环。
正确做法是把乘法改写为加法递推:设 tri = 1(对应 k = 1),每次做 tri += ++k,这样既避免乘法溢出,又天然控制 k 增长节奏。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 初始值:
long long tri = 1; int k = 1; - 循环条件用
tri ,而非 <code>tri ,否则多算一轮 - 一旦
tri == n就返回 true;若tri > n且还在增长,说明不是三角形数 - 不建议用
for (int k = 1; ; ++k)配break—— 容易漏写退出逻辑
代数法 vs 迭代法:性能和适用场景差异
代数法是 O(1),但涉及浮点开方和取整,对极小的 n(比如 n )未必比迭代快;迭代法最坏 <code>O(√n),但常数小、无浮点误差,且内存零开销。
实际选型要看场景:
- 单次判断、
n可能上亿 → 代数法更稳,只要处理好溢出和精度 - 批量判断同一组小数值(如
n ),或嵌入资源受限环境(无 <code>sqrt)→ 迭代法更可靠 - 需要同时返回对应的
k(即第几个三角形数)→ 代数法可直接算出k = (root - 1) / 2;迭代法自然得到k - 编译器未启用
-ffast-math时,sqrt可能比预期慢,这点容易被忽略
一个容易被忽略的边界:n = 1 和溢出检查
n = 1 是合法三角形数(k = 1),但代数法中 1 + 8 * n = 9,sqrt(9) = 3,(3 - 1) % 2 == 0 成立 —— 这没问题。真正危险的是 n 接近 INT_MAX 时的中间计算。
例如在 32 位 int 环境下,n = 200000000 时,8 * n = 1600000000 已接近 INT_MAX(约 2147483647),再加 1 就可能溢出。所以必须用 long long 存储判别式。
- 错误示范:
int disc = 1 + 8 * n;→ 即使n是long long,8 * n若按int算会先溢出 - 正确写法:
auto disc = 1LL + 8LL * static_cast<long long>(n);</long> - 如果输入类型不确定,优先提升到足够大的整型再运算,别依赖隐式转换
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










