两数之和

16 阅读5分钟

两数之和

给定一个整数数组 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]

代码说明:

  1. 哈希表:使用 Map 来存储数组中的元素及其索引。
  2. 遍历数组:通过 for 循环遍历数组,计算每个元素与目标值的差值 complement
  3. 查找差值:检查差值是否在哈希表中,如果在,则返回对应的索引;否则将当前元素及其索引存入哈希表。
  4. 返回结果:如果找到满足条件的两个数,返回它们的索引;否则返回空数组。

复杂度分析:

  • 时间复杂度:O(n),其中 n 是数组的长度。我们只需要遍历一次数组。
  • 空间复杂度:O(n),哈希表在最坏情况下需要存储 n 个元素。

这个方法在 JavaScript 中同样高效且易于理解,适用于大多数情况。

详解

创建哈希表并将数组中的元素和索引存储在其中,是为了快速查找某个元素是否存在于数组中,并获取其索引。这是解决“两数之和”问题的关键步骤。下面详细解释为什么需要这样做,以及它是如何工作的。

为什么需要哈希表?

在“两数之和”问题中,我们需要找到两个数,使得它们的和等于目标值 target。假设当前遍历到的元素是 nums[i],那么我们需要检查数组中是否存在另一个元素 complement = target - nums[i]

如果没有哈希表,我们需要在数组中逐个查找 complement,这样的时间复杂度是 O(n)。对于每个元素,都需要遍历一次数组,总时间复杂度会达到 O(n²),效率很低。

而哈希表的作用是:

  1. 快速查找:哈希表可以在 O(1) 的时间内判断某个值是否存在。

  2. 存储索引:哈希表不仅可以存储元素的值,还可以存储其索引,方便直接返回结果。

哈希表是如何存储元素和索引的?

在代码中,哈希表(Map 或对象)的键是数组中的元素,值是该元素的索引。例如:

const numToIndex = new Map();

当我们遍历数组时:

  1. 对于当前元素 nums[i],计算 complement = target - nums[i]

  2. 检查 complement 是否在哈希表中:

    • 如果在,说明之前已经遍历过 complement,直接返回它的索引和当前索引 i
    • 如果不在,将当前元素 nums[i] 及其索引 i 存入哈希表。

具体例子

假设数组是 nums = [2, 7, 11, 15],目标值是 target = 9

遍历过程:

  1. 第一次遍历i = 0nums[i] = 2):

    • 计算 complement = 9 - 2 = 7
    • 检查哈希表,发现 7 不存在。
    • 2 和它的索引 0 存入哈希表:numToIndex = {2: 0}
  2. 第二次遍历i = 1nums[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]

为了避免这种情况,我们采用边遍历边存储的方式:

  • 每次只存储当前元素之前的元素,确保不会重复使用当前元素。

总结

哈希表的作用是:

  1. 快速查找:判断 complement 是否存在于数组中。
  2. 存储索引:方便直接返回结果。
  3. 避免重复使用元素:通过边遍历边存储的方式,确保不会重复使用当前元素。

通过这种方式,我们可以在 O(n) 的时间复杂度内解决问题,效率非常高。

更多vue相关插件及后台管理模板可访问vue admin reference,代码详情请访问github