D

当前:LC1 · 两数之和 · 首次出现于 Day 2 · 路径:顶栏「56天打卡」→ 点击 LC 题号 → 逐题动画

LC1

两数之和 · 别暴力找, 先学会"记住见过的东西"

哈希表 · 一次遍历

每扫到一个数字, 不是去后面乱找, 而是问: 我需要的另一半, 之前出现过吗?

输入 · nums
2i=07i=111i=215i=3
下标 0 先入仓库 下标 1 来匹配
时间 O(n) · 每个元素只扫一次空间 O(n) · 哈希表存历史值核心: complement = target − nums[i]

先看暴力法翻车: 为什么需要哈希表

O(n²)暴力法 · 两层循环
2→ 试探71115
7→ 试探1115
11→ 试探15

每个数字都要重新扫一遍后面的数字。 n=4 还好, n=10⁴ 时要做 10⁸ 次比对 —— 路径乱、重复多, 大数据直接超时。

O(n)哈希优化 · 边走边记
  • 1.开一个"记忆仓库" seen (value → index)。
  • 2.扫到 nums[i] 时, 先算 need = target − nums[i]。
  • 3.查 seen 里有没有 need —— 有就立刻配对收工。
  • 4.没有就把 nums[i] 存入 seen, 下一个数来配它。

每个数字只参与"一次查 + 一次存", 总共 2n 次操作, 所以是 O(n)。

登场 · 看清题目初始化Step 1 / 6

执行舱 · 扫描机器人 + 记忆仓库

无扫描中 · 教学帧
数组传送带 · nums
  • i=02
  • i=17
  • i=211
  • i=315
扫描机器人 · complement 雷达
current = nums[i]
complement = target − current
等待扫描
能量门 target
9
待两个数加和 = 9
Seen Map · 记忆仓库
0
仓库还空着 — 还没扫到任何数。

仓库只持有"已经扫过"的元素 (nums[0..i-1])。 所以查到的下标永远 < i, 不会跟自己配对。

这一步在做什么 · 人话版

题目给我们一组数字 nums = [2, 7, 11, 15] 和 target = 9。要找到两个数, 它们的下标加起来值为 9。我们的策略不是暴力两两试, 而是开一个"记忆仓库" seen, 一边扫一边记 —— 每扫到一个数, 先问"我需要的另一半之前出现过吗?"

状态面板 · 这一帧的全部变量

i
current = nums[i]
complement
map has complement?
action
初始化

Go 解法 · 与动画同步

高亮行: 2
1func twoSum(nums []int, target int) []int {
2 seen := map[int]int{}
3
4 for i, x := range nums {
5 need := target - x
6
7 if j, ok := seen[need]; ok {
8 return []int{j, i}
9 }
10
11 seen[x] = i
12 }
13
14 return nil
15}

蓝色 = 查询补数 · 绿色 = 命中返回 · 紫色 = 存入仓库

步骤列表

点击跳转

30 秒面试回答

我用哈希表记录已经扫描过的数字和下标。遍历到 nums[i] 时, 计算 need = target − nums[i], 如果 need 已经在 map 中, 说明之前的某个数和当前数能凑成 target, 直接返回两个下标。否则把当前数字存入 map。 这样每个元素只扫描一次, 时间 O(n), 空间 O(n)。 关键点是先查再存, 避免当前元素和自己配对。

常见误区 · 别再翻车

  • 先存后查, 导致自己和自己配对
    把 seen[x] = i 写在查询之前, 当 nums[i] 恰好等于 target/2 时, seen 里立刻就有 need = x, 程序错误地返回 [i, i]。永远先 if seen[need], 再 seen[x] = i。
  • 只返回值, 不返回下标
    LC1 要求返回的是下标对 [j, i], 不是值对 [nums[j], nums[i]]。所以 seen 必须用 value → index 这种映射, 而不是 set。
  • 以为必须排序
    排序后可以用双指针 (LC167 的做法), 但 LC1 要求返回原数组下标。排序会破坏原始下标位置, 你得额外维护 [value, originalIndex] 才能恢复, 反而更麻烦。
  • 把哈希表当成排好序的结构
    Go 的 map / Java 的 HashMap 不保证遍历顺序, 也不能按 key 做范围查询。LC1 只需要等值查找, 所以哈希表足够; 如果题目变成「两数之差」, 那就要换数据结构。