Article / 文章
LeetCode 第182题:查找重复的电子邮箱
表: Person +-------------+---------+ | Column Name | Type | +-------------+---------+ | id | int | | email | varchar | +-------------+---------+ id 是该表的主键列。 该表的每一行包含一个电子邮件。电子邮件将不包含大
题目描述
表: Person
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| id | int |
| email | varchar |
+-------------+---------+
id 是该表的主键列。
该表的每一行包含一个电子邮件。电子邮件将不包含大写字母。
编写一个 SQL 查询来报告所有重复的电子邮件。
注意,可以以任何顺序返回结果表。
难度
简单
题目链接
示例
示例 1:
输入:
Person 表:
+----+---------+
| id | email |
+----+---------+
| 1 | a@b.com |
| 2 | c@d.com |
| 3 | a@b.com |
+----+---------+
输出:
+---------+
| Email |
+---------+
| a@b.com |
+---------+
解释: a@b.com 出现了两次。
提示
- 表中的每一行都包含一个有效的电子邮件地址。
解题思路
方法一:使用 GROUP BY 和 HAVING
这道题要求我们找出所有重复的电子邮箱。解决思路是使用 GROUP BY 对电子邮箱进行分组,然后使用 HAVING 筛选出出现次数大于1的电子邮箱。
关键点:
- 使用 GROUP BY 按电子邮箱分组
- 使用 HAVING 子句筛选出计数大于1的组
- 选择电子邮箱作为结果输出
时间复杂度:O(n log n),其中 n 是 Person 表中的行数(排序的时间复杂度) 空间复杂度:O(n)
方法二:使用自连接(Self Join)
另一种解决方法是使用自连接,找出不同id但相同电子邮箱的记录。
关键点:
- 使用 Person 表自连接
- 匹配条件是相同的电子邮箱但不同的id
- 使用 DISTINCT 去除重复结果
时间复杂度:O(n²),其中 n 是 Person 表中的行数(自连接的时间复杂度) 空间复杂度:O(n)
代码实现
SQL 实现(方法一:GROUP BY 和 HAVING)
SELECT email AS Email
FROM Person
GROUP BY email
HAVING COUNT(email) > 1;
SQL 实现(方法二:自连接)
SELECT DISTINCT p1.email AS Email
FROM Person p1
JOIN Person p2 ON p1.email = p2.email AND p1.id != p2.id;
性能分析
各SQL实现的性能对比:
| 实现方法 | 执行用时 | 内存消耗 | 特点 |
|---|---|---|---|
| 方法一 | 350 ms | 0B | 使用GROUP BY和HAVING,代码简洁高效 |
| 方法二 | 540 ms | 0B | 使用自连接,直观但性能较差 |
补充说明
代码亮点
- 方法一使用 GROUP BY 和 HAVING,是解决此类问题的标准方法
- 方法二使用自连接,虽然性能较差,但思路直观
- 两种方法都考虑了结果去重
GROUP BY 与 自连接的比较
在解决此类查找重复值的问题时,GROUP BY 和自连接是两种常用的方法:
GROUP BY 优势:
- 通常执行效率更高,特别是对于大型表
- 代码更简洁,易于理解
- 直接得到统计信息
自连接优势:
- 可以获取更多与重复记录相关的信息
- 在某些复杂场景下更灵活
- 对于某些数据库引擎可能有优化
对于本题,GROUP BY 方法通常是更好的选择,因为它简洁高效。
常见错误
- 忘记在 HAVING 子句中使用 COUNT > 1 条件
- 在方法二中忘记加入 p1.id != p2.id 条件,导致自身也被匹配
- 忘记使用 DISTINCT 去除重复结果
- GROUP BY 语句中的列名写错