两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:
输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:
输入:nums = [3,3], target = 6
输出:[0,1]
以下是使用 JavaScript 实现的代码,解决“两数之和”问题:
代码实现:
function twoSum(nums, target) {
const numToIndex = new Map(); // 创建一个哈希表(使用 Map)
for (let i = 0; i < nums.length; i++) {
const complement = target - nums[i]; // 计算差值
if (numToIndex.has(complement)) { // 如果差值在哈希表中
return [numToIndex.get(complement), i]; // 返回两个索引
}
numToIndex.set(nums[i], i); // 将当前元素及其索引存入哈希表
}
return []; // 如果没有找到,返回空数组(根据题目描述,这种情况不会发生)
}
示例运行:
const nums1 = [2, 7, 11, 15];
const target1 = 9;
console.log(twoSum(nums1, target1)); // 输出: [0, 1]
const nums2 = [3, 2, 4];
const target2 = 6;
console.log(twoSum(nums2, target2)); // 输出: [1, 2]
const nums3 = [3, 3];
const target3 = 6;
console.log(twoSum(nums3, target3)); // 输出: [0, 1]
代码说明:
- 哈希表:使用
Map
来存储数组中的元素及其索引。 - 遍历数组:通过
for
循环遍历数组,计算每个元素与目标值的差值complement
。 - 查找差值:检查差值是否在哈希表中,如果在,则返回对应的索引;否则将当前元素及其索引存入哈希表。
- 返回结果:如果找到满足条件的两个数,返回它们的索引;否则返回空数组。
复杂度分析:
- 时间复杂度:O(n),其中 n 是数组的长度。我们只需要遍历一次数组。
- 空间复杂度:O(n),哈希表在最坏情况下需要存储 n 个元素。
这个方法在 JavaScript 中同样高效且易于理解,适用于大多数情况。
详解
创建哈希表并将数组中的元素和索引存储在其中,是为了快速查找某个元素是否存在于数组中,并获取其索引。这是解决“两数之和”问题的关键步骤。下面详细解释为什么需要这样做,以及它是如何工作的。
为什么需要哈希表?
在“两数之和”问题中,我们需要找到两个数,使得它们的和等于目标值 target
。假设当前遍历到的元素是 nums[i]
,那么我们需要检查数组中是否存在另一个元素 complement = target - nums[i]
。
如果没有哈希表,我们需要在数组中逐个查找 complement
,这样的时间复杂度是 O(n)。对于每个元素,都需要遍历一次数组,总时间复杂度会达到 O(n²),效率很低。
而哈希表的作用是:
-
快速查找:哈希表可以在 O(1) 的时间内判断某个值是否存在。
-
存储索引:哈希表不仅可以存储元素的值,还可以存储其索引,方便直接返回结果。
哈希表是如何存储元素和索引的?
在代码中,哈希表(Map
或对象)的键是数组中的元素,值是该元素的索引。例如:
const numToIndex = new Map();
当我们遍历数组时:
-
对于当前元素
nums[i]
,计算complement = target - nums[i]
。 -
检查
complement
是否在哈希表中:- 如果在,说明之前已经遍历过
complement
,直接返回它的索引和当前索引i
。 - 如果不在,将当前元素
nums[i]
及其索引i
存入哈希表。
- 如果在,说明之前已经遍历过
具体例子
假设数组是 nums = [2, 7, 11, 15]
,目标值是 target = 9
。
遍历过程:
-
第一次遍历(
i = 0
,nums[i] = 2
):- 计算
complement = 9 - 2 = 7
。 - 检查哈希表,发现
7
不存在。 - 将
2
和它的索引0
存入哈希表:numToIndex = {2: 0}
。
- 计算
-
第二次遍历(
i = 1
,nums[i] = 7
):- 计算
complement = 9 - 7 = 2
。 - 检查哈希表,发现
2
存在,且它的索引是0
。 - 返回结果
[0, 1]
。
- 计算
为什么不能提前存储所有元素?
如果我们在遍历之前就将所有元素和索引存入哈希表,那么在查找 complement
时,可能会找到当前元素本身。例如:
nums = [3, 3], target = 6
如果提前存储所有元素,哈希表会是 {3: 1}
(后面的 3
会覆盖前面的 3
)。当遍历到第一个 3
时,计算 complement = 6 - 3 = 3
,发现 3
在哈希表中,但它的索引是 1
,这会导致返回 [1, 0]
,而实际上正确答案是 [0, 1]
。
为了避免这种情况,我们采用边遍历边存储的方式:
- 每次只存储当前元素之前的元素,确保不会重复使用当前元素。
总结
哈希表的作用是:
- 快速查找:判断
complement
是否存在于数组中。 - 存储索引:方便直接返回结果。
- 避免重复使用元素:通过边遍历边存储的方式,确保不会重复使用当前元素。
通过这种方式,我们可以在 O(n) 的时间复杂度内解决问题,效率非常高。
更多vue相关插件及后台管理模板可访问vue admin reference,代码详情请访问github