一个正整数n是三角形数当且仅当8n+1为完全平方数且其平方根为奇数;需防溢出(如n>llong_max/8时直接返回false)、用整数校验平方性、奇偶性判断代替除法验证。

什么是三角形数?直接看判定公式
一个正整数 n 是三角形数,当且仅当存在某个正整数 k,使得 n = k * (k + 1) / 2。把这个式子反解,就能得到判定条件:判断 8 * n + 1 是否为完全平方数——如果是,且其平方根为奇数,则 n 就是三角形数。
原因很简单:k² + k − 2n = 0 的求根公式给出 k = (−1 + √(1 + 8n)) / 2,所以只要 √(1 + 8n) 是整数且为奇数,k 就是正整数。
实操建议:
- 用
long long防止8 * n溢出(尤其n > 2.7e18时) - 计算平方根后,用
sqrt_val * sqrt_val == candidate验证是否真为完全平方(别信sqrt返回的浮点精度) - 检查
(sqrt_val & 1) == 1确认奇偶性,比sqrt_val % 2 == 1更快也更安全
迭代法怎么写?什么时候不该用它
迭代法就是从 k = 1 开始试,不断计算 t = k * (k + 1) / 2,直到 t >= n。如果相等就是三角形数。
它看起来直观,但实际有明显短板:
- 时间复杂度是
O(√n),而公式法是O(1)(含一次开方) - 对大数(比如
n = 1e16)要循环约1.4e8次,C++ 里可能超时或卡顿 - 中间乘法
k * (k + 1)容易溢出——即使n在int范围内,k接近√(2n)时也可能溢出int - 没有提前退出机制:必须算到 ≥
n才停,无法剪枝
完整可运行的公式法实现(带溢出防护)
下面是一个安全、跨平台可用的判定函数:
bool isTriangular(long long n) {
if (n = candidate) --root;
if (root * root != candidate) return false;
return (root & 1) == 1;
}
说明:
- 不用
std::sqrt直接转long long,因为对大整数(如2^53以上)会丢精度 - 用整数逼近修正
root,比依赖round或llround更可靠 - 最后只检查奇偶性,不除 2 再验证
k是否为整数——因为root是奇数已隐含该条件
实际使用时最容易忽略的一点
很多人在测试时只用小样例(如 1, 3, 6, 10),结果上线后遇到 n = 9223372036854775807 这类边界值就崩——不是因为逻辑错,而是 8 * n 溢出成负数,导致 sqrt 传入负参(未定义行为)或结果全乱。
真正健壮的代码必须先判断 n > LLONG_MAX / 8,此时直接返回 false(因为不可能有那么大的三角形数)。这点在竞赛或嵌入式场景里常被跳过,但一出问题极难定位。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











