前言
“两数之和”是 LeetCode 上最经典的入门题之一。它不仅考察基础的编程能力,还能让我们体会到不同算法思路的优劣。本文将用最通俗的语言,带你用 JavaScript 实现三种常见解法,并详细分析每种方法的优缺点,让零基础的小白也能轻松看懂!
题目描述
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那两个整数,并返回它们的数组下标。
示例:
输入: nums = [2, 7, 11, 15], target = 9
输出: [0, 1]
// 因为 nums[0] + nums[1] == 9
方法一:暴力解法(双重循环)
思路
最直接的办法就是:把数组里的每一对数字都加一遍,看看有没有等于目标值的。用两个 for 循环,外层选第一个数,内层选第二个数。
代码实现
var twoSum = function (nums, target) {
for (var i = 0; i < nums.length; i++) {
for (var j = i + 1; j < nums.length; j++) {
if (nums[i] + nums[j] === target) {
return [i, j];
}
}
}
};
复杂度分析
- 时间复杂度:O(n²),每个数都要和后面的数配对一次。
- 空间复杂度:O(1),没有用到额外空间。
通俗解释
就像你在一堆钥匙里找一对能开门的钥匙,你把每一把钥匙都和其他钥匙试一遍,直到找到合适的那一对。虽然简单粗暴,但效率不高。
方法二:利用 indexOf 方法
思路
我们可以用数组自带的 indexOf 方法,查找目标值减去当前数字的另一个数是否存在于数组中。注意要排除自己和自己配对的情况。
代码实现
var twoSum = function (nums, target) {
for (let i = 0; i < nums.length; i++) {
let item = target - nums[i];
let index = nums.indexOf(item);
// 不能和自己配对
if (index !== -1 && index !== i) {
return [i, index];
}
}
};
复杂度分析
- 时间复杂度:O(n²),因为
indexOf本身也是 O(n)。 - 空间复杂度:O(1)。
通俗解释
每次拿到一个钥匙,就在钥匙堆里找有没有能和它配对的钥匙(用 indexOf 查找),但不能找自己。
方法三:哈希表法(空间换时间)
思路
有没有更快的方法?有!我们可以用“空间换时间”的思路。用一个哈希表(对象)来记录已经遍历过的数字和它们的下标。每次遍历到一个新数字时,看看目标值减去这个数字的结果是不是已经在哈希表里了,如果在,说明找到了答案。
代码实现
var twoSum = function (nums, target) {
let diffs = {};
for (let i = 0; i < nums.length; i++) {
let item = target - nums[i];
if (diffs[item] !== undefined) {
return [diffs[item], i];
}
diffs[nums[i]] = i;
}
};
复杂度分析
- 时间复杂度:O(n),只需要遍历一遍数组。
- 空间复杂度:O(n),哈希表最多存下所有数字。
通俗解释
就像你在找钥匙配对时,顺手把每把钥匙的形状记在本子上。每拿到一把新钥匙,你就查查本子上有没有能和它配对的钥匙。如果有,立刻找到答案;如果没有,就把这把钥匙记下来,继续找下一把。
三种方法对比总结
| 方法 | 时间复杂度 | 空间复杂度 | 适用场景 |
|---|---|---|---|
| 暴力枚举法 | O(n²) | O(1) | 小数据量 |
| indexOf法 | O(n²) | O(1) | 小数据量 |
| 哈希表法 | O(n) | O(n) | 需要高效查找 |
- 想提升效率,哈希表法是最常用的面试解法。
indexOf方法适合理解数组查找的原理,但效率和暴力法差不多。
结语
“两数之和”虽然是 LeetCode 的入门题,但它背后蕴含的算法思想却非常重要。通过这道题,你可以学会如何用不同的思路解决同一个问题,也能体会到“空间换时间”的精髓。希望这篇文章能帮你打下坚实的算法基础,开启刷题之路!