在大屏或电脑上体验更佳——动画和操作区域更宽敞。
输入

两数之和(LeetCode #1)

两数之和要求返回数组 nums 中相加等于 target 的两个索引。一次遍历的哈希表解法在每个元素处查询“补数是否出现过”,用 O(n) 额外空间,把暴力的 O(n²) 比较降到期望 O(n) 时间。

像门口维护来客名单:新人到达,先查配对的人是否已在场;没有再登记新人。先查后写是算法的关键。

两数之和如何工作

从左到右遍历,seen 保存值到索引的映射。在 i 处计算 complement = target - nums[i]。如果补数已在表中,返回 [seen[complement], i],较早索引在前;未命中才写 seen[nums[i]] = i。

若先写再查,遇到 nums[i] == target / 2 就可能与自身配对。查旧表保证其中只含之前的索引,两个位置因此不同。

暴力法使用双循环检查 j > i 的每一对,最多 n(n − 1)/2 对,额外空间 O(1)。输入面板的解法选项可在默认哈希表和暴力之间切换,相同输入便于比较。

逐步演示

默认 nums = [2, 7, 11, 15]、target = 18,采用哈希表:

  1. i = 0、值 2:complement = 18 − 2 = 16。空表中没有 16,写 seen[2] = 0。
  2. i = 1、值 7:complement = 18 − 7 = 11。未出现,写 seen[7] = 1,表为 {2: 0, 7: 1}。
  3. i = 2、值 11:complement = 18 − 11 = 7。表中索引为 1,返回 [1, 2],不再访问 15。

切换暴力法,依次检查 2 + 7 = 9、2 + 11 = 13、2 + 15 = 17、7 + 11 = 18,四次后得到 [1, 2]。两者结果相同;规模增大时,暴力最坏检查数按平方增长,哈希表最多访问 n 个元素。

画布右侧是数组,左侧是“值 | 索引”表。每次先高亮元素、计算补数、查询字典,再把配对两处同时标绿,或写入一行(新增,值重复时覆盖原行)。暴力模式没有字典面板,显示其额外空间的区别。

时间与空间复杂度

情况暴力法哈希表法
最好O(1),首对命中O(1),索引 0、1 配对
扫描到末尾的时间O(n²)期望 O(n)
额外空间O(1)O(n)

哈希表的界依赖期望 O(1) 查询,恶劣冲突下不是无条件最坏 O(n)。默认 n = 4 时动画步数差距有限;扩大输入,才能看清平方枚举与线性遍历的增长差异。

边界情况

播放器允许 3–8 个、范围 1–99 的值,其余情况可在纸上或代码中检验。

  • 无解:原题保证恰好一解,但展示代码走到末尾时 Python 返回 None。动画明确展示无解状态,调用者应处理。
  • 两个相等值组成答案:nums = [3, 3, 4]、target = 6 时,i = 1 查到索引 0 的 3,返回 [0, 1]。先查后写保证不是自身配对。
  • 重复值不在答案中:后来的同值覆盖索引;旧索引在被覆盖前已经查过自己的补数,寻找任一合法答案仍安全。
  • 负数与零:整数键无需特别处理,只是显示输入范围不包含它们。

常见错误

  • 先插入再查询。 可能把半目标值与自己配对。
  • 返回值而非索引。 题目要位置,所以字典的值要保存索引。
  • 排序后丢失原索引。 双指针可解,但要同时携带原位置;不能直接返回排序后的索引。
  • 只用集合。 集合能回答是否出现,不能给出题目要求的位置。