3860. 不同邮件组 🔒
March 10, 2026 · View on GitHub
题目描述
给定一个字符串数组 emails,其中每个字符串是一个有效的邮件地址。
如果两个邮件地址的 规范化 本地名称和 规范化 域名名称 都相同,则属于同一组。
规范化规则如下:
- 本地名称是
'@'符号 之前 的部分。<ul> <li>忽略所有点 <code>'.'</code>。</li> <li>忽略第一个 <code>'+'</code> 之后的所有内容,如果存在的话。</li> <li>转换为小写。</li> </ul> </li> <li>域名是 <code>'@'</code> 符号 <strong>后面</strong> 的部分。 <ul> <li>转换为小写。</li> </ul> </li>
返回一个整数,表示规范化后的 不同 电子邮件组的数量。
示例 1:
输入:emails = ["test.email+alex@leetcode.com", "test.e.mail+bob.cathy@leetcode.com", "testemail+david@lee.tcode.com"]
输出:2
示例:
| 邮件地址 | 本地名称 | 规范化本地名称 | 域名 | 规范化域名 | 最终邮件地址 |
|---|---|---|---|---|---|
| test.email+alex@leetcode.com | test.email+alex | testemail | leetcode.com | leetcode.com | testemail@leetcode.com |
| test.e.mail+bob.cathy@leetcode.com | test.e.mail+bob.cathy | testemail | leetcode.com | leetcode.com | testemail@leetcode.com |
| testemail+david@lee.tcode.com | testemail+david | testemail | lee.tcode.com | lee.tcode.com | testemail@lee.tcode.com |
不同的邮件地址是 ["testemail@leetcode.com", "testemail@lee.tcode.com"]。因此,答案是 2。
示例 2:
输入:emails = ["A@B.com", "a@b.com", "ab+xy@b.com", "a.b@b.com"]
输出:2
示例:
| 邮件地址 | 本地名称 | 规范化本地名称 | 域名 | 规范化域名 | 最终邮件地址 |
|---|---|---|---|---|---|
| A@B.com | A | a | B.com | b.com | a@b.com |
| a@b.com | a | a | b.com | b.com | a@b.com |
| ab+xy@b.com | ab+xy | ab | b.com | b.com | ab@b.com |
| a.b@b.com | a.b | ab | b.com | b.com | ab@b.com |
不同的邮件地址是 ["a@b.com", "ab@b.com"]。因此,答案是 2。
示例 3:
输入:emails = ["a.b+c.d+e@DoMain.com", "ab+xyz@domain.com", "ab@domain.com"]
输出:1
解释:
| 邮件地址 | 本地名称 | 规范化本地名称 | 域名 | 规范化域名 | 最终邮件地址 |
|---|---|---|---|---|---|
| a.b+c.d+e@DoMain.com | a.b+c.d+e | ab | DoMain.com | domain.com | ab@domain.com |
| ab+xyz@domain.com | ab+xyz | ab | domain.com | domain.com | ab@domain.com |
| ab@domain.com | ab | ab | domain.com | domain.com | ab@domain.com |
所有邮件地址规范化为 "ab@domain.com"。因此,答案是 1。
提示:
1 <= emails.length <= 10001 <= emails[i].length <= 100emails[i]包含大小写英文字母,数字,以及字符'.','+'和'@'。- 每个
emails[i]包含 恰好 一个'@'字符。 - 所有本地名称和域名都不为空;本地名不能以
'+'开头。 - 域名以
".com"后缀结尾,并且在".com"之前至少包含一个字符。
解法
方法一:哈希表
我们可以使用一个哈希表 来存储每个邮箱地址的规范化结果。对于每个邮箱地址,我们按照题目要求进行规范化处理:
- 将邮箱地址分为本地名和域名两部分。
- 对于本地名,去掉所有的点
.,并且如果存在加号+,则去掉加号及其后面的部分。最后将本地名转换为小写。 - 对于域名,将其转换为小写。
- 将规范化后的本地名和域名拼接起来,得到规范化后的邮箱地址,并将其加入哈希表 中。
最后,哈希表 中的元素个数即为唯一邮箱组的数量。
时间复杂度 ,其中 和 分别是邮箱地址的数量和每个邮箱地址的平均长度。空间复杂度 ,最坏情况下所有邮箱地址都不同。
Python3
class Solution:
def uniqueEmailGroups(self, emails: list[str]) -> int:
st = set()
for email in emails:
local, domain = email.split("@")
local = local.split("+")[0].replace(".", "").lower()
domain = domain.lower()
normalized = local + domain
st.add(normalized)
return len(st)
Java
class Solution {
public int uniqueEmailGroups(String[] emails) {
Set<String> st = new HashSet<>();
for (String email : emails) {
String[] parts = email.split("@");
String local = parts[0];
String domain = parts[1];
int plusIndex = local.indexOf('+');
if (plusIndex != -1) {
local = local.substring(0, plusIndex);
}
local = local.replace(".", "").toLowerCase();
domain = domain.toLowerCase();
String normalized = local + domain;
st.add(normalized);
}
return st.size();
}
}
C++
class Solution {
public:
int uniqueEmailGroups(vector<string>& emails) {
unordered_set<string> st;
for (auto& email : emails) {
int atPos = email.find('@');
string local = email.substr(0, atPos);
string domain = email.substr(atPos + 1);
int plusPos = local.find('+');
if (plusPos != string::npos) {
local = local.substr(0, plusPos);
}
string cleaned;
for (char c : local) {
if (c != '.') {
cleaned += tolower(c);
}
}
for (char& c : domain) {
c = tolower(c);
}
st.insert(cleaned + domain);
}
return st.size();
}
};
Go
func uniqueEmailGroups(emails []string) int {
st := make(map[string]struct{})
for _, email := range emails {
parts := strings.Split(email, "@")
local := parts[0]
domain := parts[1]
if idx := strings.Index(local, "+"); idx != -1 {
local = local[:idx]
}
local = strings.ReplaceAll(local, ".", "")
local = strings.ToLower(local)
domain = strings.ToLower(domain)
normalized := local + domain
st[normalized] = struct{}{}
}
return len(st)
}
TypeScript
function uniqueEmailGroups(emails: string[]): number {
const st = new Set<string>();
for (const email of emails) {
let [local, domain] = email.split('@');
local = local.split('+')[0].replace(/\./g, '').toLowerCase();
domain = domain.toLowerCase();
const normalized = local + domain;
st.add(normalized);
}
return st.size;
}