LeetCode 第 1 题「两数之和」
字数 1753 2025-10-25 19:18:58

好的,我们这次来详细学习 LeetCode 第 1 题「两数之和」
这是 LeetCode 的第一题,也是很多人入门算法与哈希表的经典题目。


1. 题目描述

题目链接
https://leetcode.com/problems/two-sum/

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

约束条件

  • 2 <= nums.length <= 10^4
  • -10^9 <= nums[i] <= 10^9
  • -10^9 <= target <= 10^9
  • 只会存在一个有效答案

2. 题意理解

我们要在数组里找两个不同的下标 ij,使得:

\[\text{nums}[i] + \text{nums}[j] = \text{target} \]

并且同一个元素不能用两次(下标必须不同),但数组元素可能重复(如示例 3)。


3. 思路演进

3.1 暴力法(Brute Force)

最直接的想法是:

  • 用两层循环,第一层 i 从 0 到 n-1,第二层 j 从 i+1 到 n-1。
  • 检查 nums[i] + nums[j] == target,如果成立,返回 [i, j]

时间复杂度:O(n²)
空间复杂度:O(1)

缺点:当 n 最大为 10^4 时,n² 是 10^8,在 LeetCode 上可能勉强通过,但效率低。


3.2 哈希表优化思路

我们想要避免内层循环,核心问题是:
对于当前数字 nums[i],我们要快速知道 target - nums[i] 是否在数组里出现过,并且知道它的下标。

方法
用一个哈希表(字典/Map)来记录已经遍历过的数字及其下标。

  • 遍历数组,对于每个元素 nums[i],计算 complement = target - nums[i]
  • 检查 complement 是否在哈希表中:
    • 如果在,说明前面已经出现过这个补数,直接返回 [map[complement], i]
    • 如果不在,把 nums[i] 和下标 i 存入哈希表,继续遍历。

为什么可行
因为题目保证有且只有一组解,所以在找到解之前,补数一定没出现过,直到遇到配对的数时,补数已经在哈希表里。


4. 详细步骤举例

以示例 1 说明:nums = [2,7,11,15], target = 9

  1. 初始化哈希表 map = {}
  2. i=0, nums[0]=2, complement=9-2=7
    • 7 在 map 中吗?不在。
    • 把 (2,0) 存入 map → map={2:0}
  3. i=1, nums[1]=7, complement=9-7=2
    • 2 在 map 中吗?在,下标是 0。
    • 返回 [0,1]

以示例 3 说明重复元素情况:nums = [3,3], target=6

  1. map={}
  2. i=0, nums[0]=3, complement=6-3=3
    • 3 在 map 中吗?不在。
    • 存 (3,0) → map={3:0}
  3. i=1, nums[1]=3, complement=6-3=3
    • 3 在 map 中吗?在,下标是 0。
    • 返回 [0,1]
    • 注意这里虽然值相同,但下标不同,符合题意。

5. 代码实现(Python)

def twoSum(nums, target):
    hashmap = {}
    for i, num in enumerate(nums):
        complement = target - num
        if complement in hashmap:
            return [hashmap[complement], i]
        hashmap[num] = i
    return []  # 题目保证有解,这里不会执行

时间复杂度:O(n),每个元素遍历一次,哈希表操作 O(1)。
空间复杂度:O(n),哈希表最多存储 n 个元素。


6. 关键点总结

  • 利用哈希表将查找时间从 O(n) 降到 O(1),是“空间换时间”的典型例子。
  • 一次遍历即可完成,因为我们在遍历时记录之前出现过的数字,并在后续判断补数是否存在。
  • 重复元素不影响,因为我们在找到答案时,用的是之前出现的那个元素的下标,和当前下标,不会重复使用同一个元素。

这样讲解是否清晰?如果有哪部分希望我再展开或举例,请告诉我。

好的,我们这次来详细学习 LeetCode 第 1 题「两数之和」 。 这是 LeetCode 的第一题,也是很多人入门算法与哈希表的经典题目。 1. 题目描述 题目链接 : https://leetcode.com/problems/two-sum/ 题目 : 给定一个整数数组 nums 和一个整数目标值 target ,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。 你可以假设每种输入只会对应一个答案,并且你不能使用相同的元素两次。 可以按任意顺序返回答案。 示例 1 : 示例 2 : 示例 3 : 约束条件 : 2 <= nums.length <= 10^4 -10^9 <= nums[ i] <= 10^9 -10^9 <= target <= 10^9 只会存在一个有效答案 2. 题意理解 我们要在数组里找两个不同的下标 i 和 j ,使得: \[ \text{nums}[ i] + \text{nums}[ j ] = \text{target} \] 并且同一个元素不能用两次(下标必须不同),但数组元素可能重复(如示例 3)。 3. 思路演进 3.1 暴力法(Brute Force) 最直接的想法是: 用两层循环,第一层 i 从 0 到 n-1,第二层 j 从 i+1 到 n-1。 检查 nums[i] + nums[j] == target ,如果成立,返回 [i, j] 。 时间复杂度 :O(n²) 空间复杂度 :O(1) 缺点 :当 n 最大为 10^4 时,n² 是 10^8,在 LeetCode 上可能勉强通过,但效率低。 3.2 哈希表优化思路 我们想要避免内层循环,核心问题是: 对于当前数字 nums[i] ,我们要快速知道 target - nums[i] 是否在数组里出现过,并且知道它的下标。 方法 : 用一个哈希表(字典/Map)来记录已经遍历过的数字及其下标。 遍历数组,对于每个元素 nums[i] ,计算 complement = target - nums[i] 。 检查 complement 是否在哈希表中: 如果在,说明前面已经出现过这个补数,直接返回 [map[complement], i] 。 如果不在,把 nums[i] 和下标 i 存入哈希表,继续遍历。 为什么可行 : 因为题目保证有且只有一组解,所以在找到解之前,补数一定没出现过,直到遇到配对的数时,补数已经在哈希表里。 4. 详细步骤举例 以示例 1 说明: nums = [2,7,11,15], target = 9 初始化哈希表 map = {} i=0, nums[ 0 ]=2, complement=9-2=7 7 在 map 中吗?不在。 把 (2,0) 存入 map → map={2:0} i=1, nums[ 1 ]=7, complement=9-7=2 2 在 map 中吗?在,下标是 0。 返回 [ 0,1 ] 以示例 3 说明重复元素情况: nums = [3,3], target=6 map={} i=0, nums[ 0 ]=3, complement=6-3=3 3 在 map 中吗?不在。 存 (3,0) → map={3:0} i=1, nums[ 1 ]=3, complement=6-3=3 3 在 map 中吗?在,下标是 0。 返回 [ 0,1 ] 注意这里虽然值相同,但下标不同,符合题意。 5. 代码实现(Python) 时间复杂度 :O(n),每个元素遍历一次,哈希表操作 O(1)。 空间复杂度 :O(n),哈希表最多存储 n 个元素。 6. 关键点总结 利用哈希表将查找时间从 O(n) 降到 O(1),是“空间换时间”的典型例子。 一次遍历即可完成,因为我们在遍历时记录之前出现过的数字,并在后续判断补数是否存在。 重复元素不影响,因为我们在找到答案时,用的是之前出现的那个元素的下标,和当前下标,不会重复使用同一个元素。 这样讲解是否清晰?如果有哪部分希望我再展开或举例,请告诉我。