图解题库 / 数组 · 哈希表

1. 两数之和

简单 含交互动画

学完这道你应该能: 说清它为什么用「哈希表」,而不是死记步骤; 合上页面,自己默写出核心代码; 用 30 秒把思路讲清楚。

题目描述

在数组里找两个数,使它们相加等于 target,返回这两个数的下标

nums = [5, 2, 7, 11, 15]
target = 13
输出 = [1, 3] (2 + 11 = 13)

思路解析

先看最直接的笨办法:拿一个数,去和后面每个数挨个相加试试看。

笨办法 · 固定 5 挨个试:固定第一个数 5,先和 2 相加 = 7,不对。指针继续往后挪。

笨办法 · 还在试:5 和后面 7、11、15 全试完都不对,只好再固定 2,从头再来一遍。每一对都要算。

数组有 1 万个数,就要算约 1 亿 次。问题出在「每次都要回头把后面全找一遍」。

一边扫数组,一边用一个哈希表记下「见过的数 → 它的下标」。每到一个数,只要查一下「我的搭档之前记过没有」,一步就能找到。

准备开始:哈希表一开始是空的。我们从 0 号位开始,从左往右扫。

i = 0 · 看 5:当前是 5。要凑成 13,就还差一个 8。去哈希表里找 8——现在表是空的,没有。

i = 0 · 没找到:没找到搭档,就把自己记进哈希表:5 在 0 号位,写成 5 → 0。继续下一个。

i = 1 · 看 2:当前是 2,还差 11。查哈希表,只有 5,没有 11。

i = 1 · 没找到:把 2 也记进表:2 → 1

i = 2 · 看 7:当前是 7,还差 6。表里没有 6。

i = 2 · 没找到:把 7 记进表:7 → 2。注意表越来越「全」了。

i = 3 · 看 11 · 重点:当前是 11,还差 2。查哈希表——2 之前记过

i = 3 · 找到了!:哈希表里 2 → 1,说明 2 在 1 号位。再加上现在的 3 号位,搭档凑齐,返回 [1, 3],结束。

笨办法每个数都要回头找一遍,是 n×n 次;哈希表只扫一遍,一万个数从一亿次降到一万次。

「回头找」改成「记下来、秒查到」。这是算法里最常用的一招,后面很多题都会用到哈希表。

参考代码(Python)

Python
1class Solution:
2    def twoSum(self, nums, target):
3        map = dict()                 # 哈希表:值 → 下标
4        for i, num in enumerate(nums):
5            anotherNum = target - num # 还差的搭档
6            if anotherNum in map:     # 之前记过吗?
7                return [map[anotherNum], i]
8            map[num] = i              # 没有就记下自己
9        return []

复杂度分析

  • 时间复杂度:O(n) —— 数组只扫一遍
  • 空间复杂度:O(n) —— 哈希表最多存 n 个数

套路模板

记住这个骨架:先算 need、先查、再存自己。三数之和、四数之和,就是在它外面再套一层循环。

Python
1# 凡是「找一对 / 找另一半」的题都能套
2seen = {}
3for i, x in enumerate(nums):
4    need = target - x      # 想找的另一半
5    if need in seen:       # 先查
6        return [seen[need], i]
7    seen[x] = i            # 再存自己

易错点

  • 先 seen[x]=i 再查 need → ✅ 先查 need,再存自己(顺序反了,nums=[3,3] 会把自己当搭档)
  • seen 里存 下标 → 值 → ✅ 存 值 → 下标(要返回下标)(查的是 need 这个「值」,所以键必须是值)

以上文字与上方动画完全同一思路:先看动画建立直觉 → 读文字巩固 → 关掉页面自己默写一遍代码,能写出来才算真的掌握

下一题 →26. 删除有序数组中的重复项 ← 返回题库