题目描述

✅ 182. 查找重复的电子邮箱

image-20260928233442750

image-20260928233442753

题意分析

Person 中 id 唯一,但 email 可以重复。要求找出出现至少两次的邮箱,并让每个重复邮箱只输出一行。题目保证邮箱非空且不含大写字母,结果顺序任意。

这里需要统计的是每个邮箱的记录数,而不是每条记录的信息。因此先把相同 email 的行放到一组,再保留计数大于 1 的组即可。仅仅去重只能得到所有不同邮箱,无法判断哪些邮箱原来重复。

解法:SQL 分组统计

核心思路

[!blue]

GROUP BY email 把邮箱相同的记录归为一组。每组对应一个候选邮箱,COUNT(*) 统计该组包含多少行;HAVING COUNT(*) > 1 则把只出现一次的组排除。

可以按逻辑处理顺序理解:先从 Person 取得原始记录,再分组和计数,然后用 HAVING 筛选组,最后输出每组的邮箱。WHERE 过滤的是分组前的单行,此时尚没有组内总数,因此不能用它来写当前聚合条件。

分组结果已经是每个邮箱一行,投影 email AS Email 就满足结果格式,无需再次使用 DISTINCT。

解题步骤

  1. 查询 Person,按 email 分组,不能按唯一的 id 分组。
  2. 用 COUNT(*) 统计每组记录数,以 HAVING 保留大于 1 的组。
  3. 选择 email,并用别名 Email 对齐题目输出列名。

样例中的 a@b.com 对应两行,计数为 2,能够保留;c@d.com 只对应一行,被筛掉。空表不会生成任何分组,所有邮箱都不重复时也会自然返回空结果。

代码实现

SELECT email AS Email
FROM Person
GROUP BY email
HAVING COUNT(*) > 1;

复杂度分析

设表有 $N$ 行、不同邮箱有 $U$ 个。以下将单次邮箱比较或哈希的成本视为常数;实际执行计划由数据库决定。

  • 时间复杂度:哈希聚合的期望时间为 $O(N)$;若先排序再聚合,则通常为 $O(N\log(N+1))$。已有合适的邮箱索引时,也可能按索引顺序直接聚合。
  • 空间复杂度:哈希聚合需要 $O(U)$ 额外空间保存各邮箱计数;排序聚合的内存和临时磁盘用量取决于排序方式。

关键点总结

[!green]

  • 分组列决定统计对象:本题统计邮箱,所以分组键是 email。
  • COUNT(*) 统计组内行数;题目保证 email 非空,所以这里 COUNT(email) 也等价。
  • 筛选聚合值用 HAVING;它判断整个组是否应出现在结果中。
  • 输出不需要计数列,计数只用于筛选,也不需要额外去重。

易错点总结

[!yellow]

  • 在 WHERE 中使用 COUNT(*):此时还没有分组结果,聚合函数不能这样用于行过滤。
  • 按 id 分组:每个主键只对应一行,永远找不到计数大于 1 的组。
  • 只写 DISTINCT email:会把只出现过一次的邮箱也输出,无法表达“重复”。
  • 把阈值写成 >= 1:每个已有分组都满足,必须要求至少两行。
  • 选择未分组的 id:同一重复邮箱对应多个编号,没有唯一应输出的编号;本题只要求邮箱列。

相似题目

题目 难度 关联与区别
196. 删除重复的电子邮箱 简单 先识别重复邮箱,再进一步删除重复行;本题只做分组查询,不改变表数据。
转载与许可
作者
链接 https://hgnulb.github.io/blog/2026/16589525
许可 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!