Set集合是查重机制的底层支撑,依托唯一性和O(1)查找特性跳过重复计算;其本质是用哈希判断替代逐个比对,依赖对象可哈希性及正确实现hashCode/equals。

Set 集合在搜索算法中构建查重机制,核心在于利用其 唯一性 + O(1) 查找 特性,跳过重复计算、避免冗余访问,显著提升效率。它不是“辅助工具”,而是查重逻辑的底层支撑。
查重机制的本质:用哈希判断代替逐个比对
传统列表查重需遍历比较(O(n)),而 set 依靠哈希表实现:插入或查询时,先算元素哈希值定位桶位置,再用 equals(或 ==)确认是否已存在。只要对象可哈希(Python 中为不可变类型;Java 中需正确重写 hashCode/equals),就能在常数时间内完成“这个值来过没?”的判断。
- Python 中:
'a' in my_set比'a' in my_list快一个数量级以上,尤其数据量大时 - Java 中:
set.contains(obj)底层调用hashCode()和equals(),缺一不可;若未重写,仅比较内存地址,查重会失效 - C++ STL 的
std::set虽基于红黑树(O(log n)),但仍是有序查重首选;而std::unordered_set才对应哈希 O(1),更贴近通用“查重”场景
典型搜索场景中的查重落地方式
查重不是独立步骤,而是嵌入搜索流程的关键拦截点:
- 广度优先搜索(BFS)去重访问:将已访问节点存入 set,每次生成新状态前先查 set,避免重复入队。例如迷宫路径、单词接龙中,“hit → hot → lot”和“hit → lot”若不查重,lot 会被多次处理
- 回溯剪枝中的状态去重:在排列/子集问题中,输入含重复元素(如 [1,2,2]),先排序,再用 set 记录本轮递归中已选过的值,跳过相同数字的重复分支
-
最长连续序列类问题:如 LeetCode 128,先转为 set,再只从“无前驱数”(
num-1 not in num_set)开始扩展,直接跳过中间值,把时间从 O(n²) 降到 O(n)
实际编码中容易踩的坑
查重失效往往不是逻辑错,而是基础细节疏忽:
- Python 空集合必须写
set(),写成{}是空字典,后续.add()会报错 - Java 使用自定义对象进 HashSet 时,必须同时重写
hashCode()和equals(),且二者逻辑一致(例如都基于 id 字段) - Python set 不支持列表、字典等可变类型作为元素,若需对字典去重,可转为 frozenset 或 tuple 形式暂存键值对
- Redis 的
SET类型天然适合分布式查重,比如用户行为去重统计——同一用户 ID 多次写入,自动只留一份,且SADD返回值能直接判断是否为首次出现
查重机制是否高效,不取决于你用了 set,而取决于你是否把它放在了搜索路径的“入口关卡”上。一次哈希判断,省下的是整棵子树的无效展开。

















