专栏其他内容:
LeetCode Hot100 中 enumerate 函数的妙用(2026.2月版)
LeetCode Hot100数据结构背景知识之列表(List)Python2026新版
LeetCode Hot100数据结构背景知识之元组(Tuple)Python2026新版
LeetCode Hot100数据结构背景知识之集合(Set)Python2026新版
LeetCode Hot100数据结构背景知识之字典(Dictionary)Python2026新版
一、set数据结构背景
LeetCode Hot100中,"去重"和"频繁判断元素是否存在"是高频需求,而我们最熟悉的列表(list),其查找操作的时间复杂度是O(n)------需要遍历整个列表才能确定元素是否存在,去重也需借助循环或字典,效率低下。
集合(set)的出现,正是为了解决这一痛点。它的底层基于**哈希表(Hash Table)**实现,核心逻辑的是:将元素通过哈希函数映射到哈希表的索引位置,若两个元素哈希值相同(即哈希冲突),则通过链表或红黑树解决。这种实现让set的核心操作(添加、删除、查找)平均时间复杂度均为O(1),远优于list的O(n),这也是刷题中优先用set处理去重和查找的核心原因。
二、set核心特性
set的所有特性都围绕**"去重""快速查找"**设计:
-
无序性 :元素无固定插入顺序,不支持索引和切片(这是与list、tuple的核心区别)。刷题中若需"有序去重",需先通过set去重,再用sorted()排序(如
sorted(set(nums))),不可直接遍历set依赖顺序。 -
唯一性 :自动去除重复元素,无论插入多少个重复值,set中仅保留一个。这是set最常用的特性,比如快速去除数组中的重复元素,一行代码即可实现:
unique_nums = set(nums)。 -
可哈希性限制 :set中的元素必须是可哈希对象(如int、str、tuple),不可哈希对象(如list、dict)无法加入set。示例:
s = {1, 2}合法,s = {[1, 2]}会直接报错------刷题中若需存储多个值,可先将其转为tuple,再加入set。 -
支持集合运算:内置交集(&)、并集(|)、差集(-)、对称差集(^)等操作,无需手动循环判断,可快速处理"两个集合的关系",对应LeetCode中《两个数组的交集》等高频题目。
三、set常用函数
set的函数均围绕其"可变、唯一、无序"特性设计,核心分为「添加、删除、查询、集合运算、转换」5大类,每类函数都标注了用法、示例和刷题备注,贴合LeetCode实战场景,直接套用即可:
1. 添加类函数(动态补充元素)
-
set.add(x) :向集合中添加单个元素x(x必须是可哈希对象),若x已存在,不做任何操作(避免重复)。 示例:
s = {1, 2},s.add(3)→{1, 2, 3};s.add(2)→ 无变化。 【注:常用于遍历过程中动态添加元素(如《两数之和》中,遍历数组时添加元素到set,用于后续快速查找目标补数)。】 -
set.update(iterable) :向集合中添加可迭代对象(如列表、元组、字符串)中的所有元素,自动去重。 示例:
s = {1, 2},s.update([2, 3, 4])→{1, 2, 3, 4}。 【注:常用于批量添加多个元素(如将两个数组转为set后,快速合并所有元素)。】
2. 删除类函数(安全移除元素)
-
set.remove(x) :从集合中删除元素x,若x不存在,直接报错(KeyError)。 示例:
s = {1, 2, 3},s.remove(2)→{1, 3};s.remove(4)→ 报错。 【注:刷题中需确保x存在(如先通过if x in s判断),否则不推荐使用。】 -
set.discard(x) :从集合中删除元素x,若x不存在,不做任何操作(无报错)。 示例:
s = {1, 2, 3},s.discard(2)→{1, 3};s.discard(4)→ 无变化。 【注:刷题首选删除函数,避免因元素不存在导致代码报错(如《全排列II》中删除候选元素)。】 -
set.pop() :随机删除集合中的一个元素,并返回该元素(因set无序,无法指定删除位置,建议不要使用 )。 示例:
s = {1, 2, 3},s.pop()→ 可能返回1、2或3,删除后集合对应减少该元素。 -
set.clear() :清空集合中的所有元素,返回空集合。 示例:
s = {1, 2, 3},s.clear()→set()。
3. 查询类函数(快速判断/统计)
-
len(set) :统计集合中元素的个数,与list、tuple的len()用法一致。 示例:
s = {1, 2, 3},len(s)→ 3。 【注:高频用法,如《存在重复元素》中,通过len(set(nums)) != len(nums)判断是否有重复元素。】 -
x in set :判断元素x是否在集合中,返回布尔值(True/False),平均时间复杂度O(1)。 示例:
s = {1, 2, 3},2 in s→ True;4 in s→ False。 【注:刷题核心用法,替代list的in操作(O(n)复杂度),如《两数之和》《三数之和》中查找目标元素。】
4. 集合运算类函数(处理两个集合关系)
-
set.intersection(set2) :返回两个集合的交集(等价于
set & set2),不修改原集合。 示例:s1 = {1, 2, 3},s2 = {2, 3, 4},s1.intersection(s2)→{2, 3}。 【注:对应《两个数组的交集》题目,直接获取两个集合的公共元素。】 -
set.union(set2) :返回两个集合的并集(等价于
set | set2),不修改原集合,自动去重。 示例:s1 = {1, 2},s2 = {3, 4},s1.union(s2)→{1, 2, 3, 4}。 -
set.difference(set2) :返回set中存在、set2中不存在的元素(等价于
set - set2),不修改原集合。 示例:s1 = {1, 2, 3},s2 = {2, 4},s1.difference(s2)→{1, 3} -
set.symmetric_difference(set2) :返回两个集合中互不相同的元素(等价于
set ^ set2),不修改原集合。 示例:s1 = {1, 2, 3},s2 = {2, 3, 4},s1.symmetric_difference(s2)→{1, 4}。
5. 转换类函数(适配不同场景)
-
tuple(set) / list(set) :将集合转为元组或列表(注意:转换后无序)。 示例:
s = {3, 1, 2},list(s)→[1, 2, 3](顺序不固定);tuple(s)→(1, 2, 3)。 【注:刷题中常用于"去重后需有序"的场景(如先转为set去重,再用sorted()排序,最后转为list)。】 -
set(iterable) :将可迭代对象(如列表、元组)转为集合,自动去重。 示例:
nums = [1, 2, 2, 3],s = set(nums)→{1, 2, 3}。 【注:最高频的用法,快速实现数组去重。】
四、重点补充:集合的a^b运算
在set的集合运算中,a ^ b(对称差集)是高频且易与其他运算混淆的知识点,单独拆解详解,贴合LeetCode刷题场景,帮你彻底避开误区:
-
运算含义 :
a ^ b表示「对称差集」,核心是返回"只在a中、或只在b中,不在两个集合的交集中"的所有元素,等价于(a - b) | (b - a),也等价于a.symmetric_difference(b) -
核心特点:不修改原集合a和b,返回一个新的集合;结果中不包含a和b的公共元素,只保留两者的"独有元素"。
刷题高频示例:
示例1:基础用法------提取两个数组的独有元素 a = {1, 2, 3, 4}(对应数组[1,2,3,4]),b = {3, 4, 5, 6}(对应数组[3,4,5,6]) a ^ b → {1, 2, 5, 6}(1、2仅在a中,5、6仅在b中,3、4是公共元素,不保留)。
示例2:刷题实战场景------《两个数组的差异》 题目要求:给定两个整数数组nums1和nums2,返回所有不在两个数组中同时出现的元素,用集合运算快速求解: nums1 = [1,2,3,4],nums2 = [3,4,5,6] s1 = set(nums1),s2 = set(nums2) result = list(s1 ^ s2) → [1,2,5,6]
避坑点:
-
❌ 误区1:混淆
a^b与a|b------a|b是并集,保留a和b的所有元素(去重),包含公共元素;而a^b不包含公共元素,只保留独有元素。 -
❌ 误区2:认为
a^b会修改原集合------与所有set集合运算一致,a^b返回新集合,原集合a和b的元素不变,刷题中可放心使用,无需担心破坏原数据。 ✅ 技巧:刷题中若遇到"找两个集合的独有元素""排除公共元素"的需求,优先用a^b,比(a - b) | (b - a)更简洁,代码可读性更高。
与其他相关运算的对比 : a = {1, 2, 3, 4},b = {3, 4, 5, 6}
a & b(交集):只保留公共元素 → {3,4}
a | b(并集):保留所有元素(去重) → {1,2,3,4,5,6}
a - b(差集):只保留a的独有元素 → {1,2}
a ^ b(对称差集):保留a和b的独有元素 → {1,2,5,6}
五、LeetCode Hot100刷题高频用法
用法1:快速去重
场景:题目要求"去除重复元素""判断是否有重复元素"(如《存在重复元素》《删除有序数组中的重复项》)。
示例:判断数组中是否有重复元素,用set一行搞定(LeetCode 217. 存在重复元素):
python
def containsDuplicate(nums):
return len(set(nums)) != len(nums)
解析:将数组转为set后,重复元素会被自动去除,若set长度与原数组不同,则存在重复元素,时间复杂度O(n)(遍历数组转为set),空间复杂度O(n)(存储set),是该题最简洁高效的解法。
用法2:快速查找(替代list的in操作,提升效率)
场景:需要频繁判断"某个元素是否存在"(如《两数之和》《三数之和》《缺失的第一个正数》),用set的in操作替代list的in操作,将时间复杂度从O(n)降至O(1)。
示例:《两数之和》优化解法(LeetCode 1. 两数之和),用set替代dict,简化代码:
python
def twoSum(nums, target):
s = set()
for i, num in enumerate(nums):
complement = target - num
if complement in s: # O(1)查找,比list的in操作快得多
return [nums.index(complement), i]
s.add(num)
用法3:集合运算(处理两个数组的关系)
核心运算示例:
- 《两个数组的交集》(LeetCode 349):返回两个数组的公共元素,用交集运算:
python
def intersection(nums1, nums2): return list(set(nums1) & set(nums2))
- 《两个数组的差集》:返回nums1中存在、nums2中不存在的元素,用差集运算:
python
def difference(nums1, nums2): return list(set(nums1) - set(nums2))
- 提取两个数组的独有元素:用对称差集运算
a^b,如前面的实战示例。
用法4:辅助去重(回溯/排列组合题目)
场景:《全排列II》《子集II》等题目,需要避免重复的排列或子集,用set存储中间结果,自动去重,简化剪枝逻辑(无需手动判断重复元素)。
示例:《全排列II》(LeetCode 47)辅助去重思路:
python
def permuteUnique(nums):
res = []
def backtrack(path, used):
if len(path) == len(nums):
res.append(path.copy())
return
s = set() # 用set存储当前层的候选元素,避免重复选择
for i in range(len(nums)):
if used[i] or nums[i] in s:
continue
s.add(nums[i])
used[i] = True
path.append(nums[i])
backtrack(path, used)
path.pop()
used[i] = False
backtrack([], [False]*len(nums))
return res
解析:用set存储当前递归层的候选元素,若元素已在set中,说明已选择过,跳过即可,无需复杂的剪枝判断,大幅简化代码。
六、高频误区
-
❌ 误区1:依赖set的顺序------set是无序的,若刷题中需要"有序输出",需先转为set去重,再用sorted()排序,示例:
sorted(set(nums)),不可直接遍历set后输出(顺序不确定,会导致答案错误)。 -
❌ 误区2:尝试将不可哈希对象加入set------list、dict无法作为set的元素,若需存储多个值(如坐标),可先转为tuple,示例:
s.add((1, 2))合法,s.add([1, 2])报错。 -
❌ 误区3:混淆remove()和discard()------remove(x)若x不存在会报错,discard(x)不会,刷题中优先用discard(x),尤其是不确定元素是否存在的场景(如删除候选元素)。
-
❌ 误区4:过度使用set------set虽高效,但需额外占用内存(空间复杂度O(n)),若题目要求"空间复杂度O(1)"(如《删除有序数组中的重复项》进阶要求),则不可用set,需用双指针法。