将所有数字加到给定的数字
重要性:5
编写一个函数 sumTo(n)
来计算数字 1 + 2 + ... + n
的总和。
例如
sumTo(1) = 1
sumTo(2) = 2 + 1 = 3
sumTo(3) = 3 + 2 + 1 = 6
sumTo(4) = 4 + 3 + 2 + 1 = 10
...
sumTo(100) = 100 + 99 + ... + 2 + 1 = 5050
制作 3 种解决方案变体
- 使用 for 循环。
- 使用递归,因为
sumTo(n) = n + sumTo(n-1)
对于n > 1
。 - 使用算术级数公式。
结果示例
function sumTo(n) { /*... your code ... */ }
alert( sumTo(100) ); // 5050
附注:哪种解决方案变体最快?最慢?为什么?
P.P.S. 我们能用递归来计算 sumTo(100000)
吗?
使用循环的解决方案
function sumTo(n) {
let sum = 0;
for (let i = 1; i <= n; i++) {
sum += i;
}
return sum;
}
alert( sumTo(100) );
使用递归的解决方案
function sumTo(n) {
if (n == 1) return 1;
return n + sumTo(n - 1);
}
alert( sumTo(100) );
使用公式的解决方案:sumTo(n) = n*(n+1)/2
function sumTo(n) {
return n * (n + 1) / 2;
}
alert( sumTo(100) );
P.S. 自然,公式是最快的解决方案。它对任何数字 n
只需执行 3 个操作。数学的力量!
循环变体在速度上排名第二。在递归和循环变体中,我们都对相同的数字求和。但递归涉及嵌套调用和执行堆栈管理。这也需要资源,因此它更慢。
P.P.S. 一些引擎支持“尾调用”优化:如果递归调用是函数中的最后一个调用,并且没有其他计算执行,那么外部函数将不需要恢复执行,因此引擎不需要记住其执行上下文。这消除了对内存的负担。但是,如果 JavaScript 引擎不支持尾调用优化(大多数引擎不支持),则会发生错误:最大堆栈大小超出,因为通常对总堆栈大小有限制。