349. 两个数组的交集(Intersection of Two Arrays)

难度:简单 | 主题:哈希表 / 集合 / 双指针

题目

给定两个数组 nums1 和 nums2,返回它们的交集。输出结果中的每个元素一定是唯一的。可以不考虑输出结果的顺序。

示例

 
输入:nums1 = [1,2,2,1], nums2 = [2,2]
 
输出:[2]
 

思路

先讲个故事:两个歌单找共同歌曲

你和朋友各自有一个歌单(可能有重复歌曲)。你想找出两个歌单里都有的歌,并且每首歌只算一次。

你把自己的歌单抄在一张白纸上(集合——曲目不重复)。然后你拿着朋友歌单的每首歌去白纸上核对:在白纸上就加入结果。

这就是集合求交集的全部过程。


引导式推导:从暴力到标准

暴力法:两层循环,每对比较。O(n×m)。

优化 ① —— 集合去重 + 哈希查找:把其中一个数组转成集合,遍历另一个数组时用 O(1) 的集合查找代替 O(n) 的列表查找。


graph LR

    A["nums1<br/>[1,2,2,1]"] --> Set["set(nums1)<br/>{1,2}"]

    B["nums2<br/>[2,2]"] --> C{"x in set1?"}

    Set --> C

    C -->|是| Result["结果 [2]"]

    C -->|否| X["跳过"]

优化 ② —— 遍历小集合:先比较两个集合长度,遍历较小的那个。这样总查找开销是 O(min(m, n))。

做法时间空间说明
集合O(m + n)O(m + n)去重 + O(1) 查找
排序 + 双指针O(m log m + n log n)O(log m + log n)排序后同步扫描

另一种思路:排序 + 双指针

两数组排序后,各一个指针同步扫描:

  • 相等 → 加入结果,跳过重复,两指针同时移动

  • 不相等 → 移动指向较小值的指针

集合法更直观,双指针法空间更优(不计排序栈空间)。


代码

 
def intersection(self, nums1, nums2):
 
    set1 = set(nums1)                     # 去重 + O(1) 查找表
 
    set2 = set(nums2)                     # 同理
 
    if len(set1) > len(set2):             # 遍历较小的集合
 
        return [x for x in set2 if x in set1]  # 小 set2 的元素在大 set1 中?
 
    return [x for x in set1 if x in set2] # 否则遍历 set1
 

复杂度

指标解释
时间O(m + n)建集合 + 遍历小集合 O(min(m, n))
空间O(m + n)两个集合

实战考量

频率分析

出现在:一面简单题,考察基础集合运用。重点在于你能否说清楚为什么集合比列表快

延伸思考

Q:为什么列表的 in 是 O(n),集合的 in 是 O(1)?

A:列表存储是无序的线性结构,必须从头遍历;集合基于哈希表,通过哈希值直接定位桶,平均 O(1)。

Q:如果两个数组都已排序呢?

A:双指针同步扫描,O(m + n) 时间,O(1) 额外空间(不计排序栈)。

Q:如果一个数组很大无法全部放进内存呢?

A:小数组建集合放内存,大数组分批从磁盘读入,逐个查集合。这叫外部哈希连接

Q:如果要求结果的输出顺序和输入中出现的顺序一致?

A:用 LinkedHashSet(Java)或 dict 保持插入顺序(Python 3.7+ dict 有序)。

易错点

  • 结果必须去重(集合天生去重,但如果是列表推导要注意)

  • 遍历小集合 + 查大集合,比反过来更优

  • 列表 in 是 O(n),集合 in 是 O(1)——这个差距决定大输入能不能过


生活类比

集合 → O(1) 查找 → 交集

想象你在一个大型图书馆找书。如果书是按编号排序的索引(哈希表),你查到一本书需要 1 秒。如果书是随机堆在地上的(列表),找一本书需要从第一本翻到最后一本。

集合就是把”随机堆在地上”变成了”按索书号整齐排列”。数据结构的选择决定了你的算法是 O(n) 还是 O(1)


相关题目

题目关系
350两个数组的交集II同族进阶,需考虑出现次数(Counter)
217存在重复元素集合的另一经典应用
349两个数组的交集本题

→ 返回题单:LeetCode学习路线图 > 一、数组与哈希(含双指针、矩阵)

速记卡(面试闪卡)

Q1:一句话讲清「349. 两个数组的交集(Intersection of Two Arrays)」到底是什么?

A:两数组交集用集合去重后 O(1) 互查,把暴力 O(n×m) 降成 O(m+n) 且结果天然唯一。

Q2:题目与本质 —— 怎么理解?

A:返回两数组都有的元素且每个只算一次;本质是把”随机堆地上的书”变成”按索书号排好”的查找题(Set 集合)。

Q3:思路:歌单找共同 —— 怎么理解?

A:像两人歌单找共同歌曲,抄一张不重复的白纸去核对;集合去重 + 哈希查找替代列表 O(n) 遍历(Set Intersection 集合求交)。

Q4:代码与优化 —— 怎么理解?

A:建两个集合、遍历较小的那个查大的,总开销 O(min(m,n)),省掉一半查找(Smaller-Set First 遍历小集合)。

Q5:复杂度与实战 —— 怎么理解?

A:时间 O(m+n)、空间 O(m+n);已排序可双指针 O(1) 空间,大数组放不下就分批外部哈希连接(External Hash Join 外部哈希连接)。

Q6:核心速记主线有哪些?

  • 结果必须去重,集合天生去重

  • 列表 in 是 O(n)、集合 in 是 O(1)

  • 遍历小集合查大集合更优

  • 已排序走双指针,空间更省

口诀

A:两单歌单找共鸣,抄纸核对不落空;

集合去重 O(1),列表遍历太苦衷;

小集查大集更省,双指针排好也通;

交集唯一不重复,哈希一击就命中。

相关链接