计算从 1 开始的前 n 个奇数的和,这是一个常见的数学问题,也是编程练习中经常遇到的题目。解决这个问题的方法不止一种,从最直接的循环累加,到巧妙利用数学规律,不同的方法展现了不同的编程思维和效率。今天,我们就来探讨如何用两种方式来实现这个功能。
我们需要编写一个函数,接收一个正整数 n
作为输入,并返回从 1 开始的前 n
个奇数的总和。
例如:
n
为 1 时,求 1 的和,结果是 1。n
为 2 时,求 1, 3 的和,结果是 4。n
为 3 时,求 1, 3, 5 的和,结果是 9。n
为 4 时,求 1, 3, 5, 7 的和,结果是 16。最直观的想法是,我们可以生成从 1 开始的前 n
个奇数,并将它们逐一相加。
/**
* 求:从1开始的前n个奇数和
*
* 输入1,求1的和
* 输入2,求1,3的和
* 输入3,求1,3,5的和
* 输入4,求1,3,5,7的和
*/
// 第一种方法:循环累加
function sum(n) {
let result = 0; // 初始化总和为 0
for (let i = 0; i < n; i++) {
// 循环 n 次,生成前 n 个奇数
// 第一个奇数 (i=0) 是 2*0+1 = 1
// 第二个奇数 (i=1) 是 2*1+1 = 3
// 第三个奇数 (i=2) 是 2*2+1 = 5
// ...
// 第 n 个奇数 (i=n-1) 是 2*(n-1)+1
result += 2 * i + 1; // 将当前奇数加到总和中
}
return result; // 返回最终的总和
}
console.log(sum(1)); // 1
console.log(sum(2)); // 4
console.log(sum(3)); // 9
console.log(sum(4)); // 16
console.log(sum(5)); // 25
思路解析:
result
来存储总和,最初为 0。for
循环,循环 n
次。循环变量 i
从 0 开始递增到 n-1
。i+1
个奇数(也就是当循环变量为 i
时)可以表示为 2 * i + 1
。result
中。result
就存储了前 n
个奇数的总和,将其返回。这种方法简单直观,易于理解,是解决这类问题的基本思路。它的时间复杂度是 O(n),因为需要循环 n 次。
仔细观察前面计算的结果:
我们发现,前 n 个奇数的和似乎总是等于 n 的平方!即:
1 = 1 * 1
1 + 3 = 4 = 2 * 2
1 + 3 + 5 = 9 = 3 * 3
1 + 3 + 5 + 7 = 16 = 4 * 4
1 + 3 + 5 + 7 + 9 = 25 = 5 * 5
这个规律是真实存在的。从 1 开始的前 n 个奇数的和恰好等于 n 的平方。
有了这个发现,我们可以写出更简洁高效的代码:
// 第二种方法:利用数学规律
function sum(n) {
return n * n; // 直接返回 n 的平方
}
console.log(sum(1)); // 1
console.log(sum(2)); // 4
console.log(sum(3)); // 9
console.log(sum(4)); // 16
console.log(sum(5)); // 25
思路解析:
这种方法直接利用了数学规律,函数只需要接收 n
,然后计算 n * n
并返回即可。
这种方法的优势在于它的效率。它的时间复杂度是 O(1),因为无论 n
有多大,它都只需要一次乘法运算。这在处理非常大的 n
值时尤为重要。
为什么前 n 个奇数的和等于 n 的平方呢?这里提供一个简单的几何解释:
考虑一个边长为 n
的正方形,它可以被分成 n * n
个小正方形。我们可以用“L形”来填充这个正方形:
n
个“L形”包含 2n - 1
个格子(第 n 个奇数)。将这 n 个“L形”叠加起来,正好组成一个 n * n
的正方形。因此,前 n 个奇数的总和就等于 n * n
。
在实际开发中,如果性能不是极致要求,方法一的可读性可能更高一些。但如果需要处理大量数据或者追求最高效率,方法二无疑是更好的选择。了解并掌握这两种不同的解决思路,可以帮助我们更好地选择合适的算法来解决问题。