Skip to content

Commit 9b7a059

Browse files
authored
feat: add solutions for lc No.3860 (#5060)
1 parent ec962fe commit 9b7a059

10 files changed

Lines changed: 841 additions & 1 deletion

File tree

Lines changed: 368 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,368 @@
1+
---
2+
comments: true
3+
difficulty: 中等
4+
edit_url: https://github.com/doocs/leetcode/edit/main/solution/3800-3899/3860.Unique%20Email%20Groups/README.md
5+
---
6+
7+
<!-- problem:start -->
8+
9+
# [3860. Unique Email Groups 🔒](https://leetcode.cn/problems/unique-email-groups)
10+
11+
[English Version](/solution/3800-3899/3860.Unique%20Email%20Groups/README_EN.md)
12+
13+
## 题目描述
14+
15+
<!-- description:start -->
16+
17+
<p>You are given an array of strings <code>emails</code>, where each string is a valid email address.</p>
18+
19+
<p>Two email addresses belong to the same group if <strong>both</strong> their <strong>normalized</strong> local names and <strong>normalized</strong> domain names are <strong>identical</strong>.</p>
20+
21+
<p>The normalization rules are as follows:</p>
22+
23+
<ul>
24+
<li>The local name is the part <strong>before</strong> the <code>&#39;@&#39;</code> symbol.
25+
26+
<ul>
27+
<li>Ignore all dots <code>&#39;.&#39;</code>.</li>
28+
<li>Ignore everything after the first <code>&#39;+&#39;</code>, if present.</li>
29+
<li>Convert to lowercase.</li>
30+
</ul>
31+
</li>
32+
<li>The domain name is the part <strong>after</strong> the <code>&#39;@&#39;</code> symbol.
33+
<ul>
34+
<li>Convert to lowercase.</li>
35+
</ul>
36+
</li>
37+
38+
</ul>
39+
40+
<p>Return an integer denoting the number of <strong>unique</strong> email groups after normalization.</p>
41+
42+
<p>&nbsp;</p>
43+
<p><strong class="example">Example 1:</strong></p>
44+
45+
<div class="example-block">
46+
<p><strong>Input:</strong> <span class="example-io">emails = [&quot;test.email+alex@leetcode.com&quot;, &quot;test.e.mail+bob.cathy@leetcode.com&quot;, &quot;testemail+david@lee.tcode.com&quot;]</span></p>
47+
48+
<p><strong>Output:</strong> <span class="example-io">2</span></p>
49+
50+
<p><strong>Explanation:</strong></p>
51+
</div>
52+
53+
<table style="border: 1px solid black;">
54+
<thead>
55+
<tr>
56+
<th style="border: 1px solid black;">Email</th>
57+
<th style="border: 1px solid black;">Local</th>
58+
<th style="border: 1px solid black;">Normalized Local</th>
59+
<th style="border: 1px solid black;">Domain</th>
60+
<th style="border: 1px solid black;">Normalized Domain</th>
61+
<th style="border: 1px solid black;">Final Email</th>
62+
</tr>
63+
</thead>
64+
<tbody>
65+
<tr>
66+
<td style="border: 1px solid black;">test.email+alex@leetcode.com</td>
67+
<td style="border: 1px solid black;">test.email+alex</td>
68+
<td style="border: 1px solid black;">testemail</td>
69+
<td style="border: 1px solid black;">leetcode.com</td>
70+
<td style="border: 1px solid black;">leetcode.com</td>
71+
<td style="border: 1px solid black;">testemail@leetcode.com</td>
72+
</tr>
73+
<tr>
74+
<td style="border: 1px solid black;">test.e.mail+bob.cathy@leetcode.com</td>
75+
<td style="border: 1px solid black;">test.e.mail+bob.cathy</td>
76+
<td style="border: 1px solid black;">testemail</td>
77+
<td style="border: 1px solid black;">leetcode.com</td>
78+
<td style="border: 1px solid black;">leetcode.com</td>
79+
<td style="border: 1px solid black;">testemail@leetcode.com</td>
80+
</tr>
81+
<tr>
82+
<td style="border: 1px solid black;">testemail+david@lee.tcode.com</td>
83+
<td style="border: 1px solid black;">testemail+david</td>
84+
<td style="border: 1px solid black;">testemail</td>
85+
<td style="border: 1px solid black;">lee.tcode.com</td>
86+
<td style="border: 1px solid black;">lee.tcode.com</td>
87+
<td style="border: 1px solid black;">testemail@lee.tcode.com</td>
88+
</tr>
89+
</tbody>
90+
</table>
91+
92+
<p>Unique emails are [<code>&quot;testemail@leetcode.com&quot;</code>, <code>&quot;testemail@lee.tcode.com&quot;</code>]. Thus, the answer is 2.</p>
93+
94+
<p><strong class="example">Example 2:</strong></p>
95+
96+
<div class="example-block">
97+
<p><strong>Input:</strong> <span class="example-io">emails = [&quot;A@B.com&quot;, &quot;a@b.com&quot;, &quot;ab+xy@b.com&quot;, &quot;a.b@b.com&quot;]</span></p>
98+
99+
<p><strong>Output:</strong> <span class="example-io">2</span></p>
100+
101+
<p><strong>Explanation:</strong></p>
102+
103+
<table style="border: 1px solid black;">
104+
<thead>
105+
<tr>
106+
<th style="border: 1px solid black;">Email</th>
107+
<th style="border: 1px solid black;">Local</th>
108+
<th style="border: 1px solid black;">Normalized Local</th>
109+
<th style="border: 1px solid black;">Domain</th>
110+
<th style="border: 1px solid black;">Normalized Domain</th>
111+
<th style="border: 1px solid black;">Final Email</th>
112+
</tr>
113+
</thead>
114+
<tbody>
115+
<tr>
116+
<td style="border: 1px solid black;">A@B.com</td>
117+
<td style="border: 1px solid black;">A</td>
118+
<td style="border: 1px solid black;">a</td>
119+
<td style="border: 1px solid black;">B.com</td>
120+
<td style="border: 1px solid black;">b.com</td>
121+
<td style="border: 1px solid black;">a@b.com</td>
122+
</tr>
123+
<tr>
124+
<td style="border: 1px solid black;">a@b.com</td>
125+
<td style="border: 1px solid black;">a</td>
126+
<td style="border: 1px solid black;">a</td>
127+
<td style="border: 1px solid black;">b.com</td>
128+
<td style="border: 1px solid black;">b.com</td>
129+
<td style="border: 1px solid black;">a@b.com</td>
130+
</tr>
131+
<tr>
132+
<td style="border: 1px solid black;">ab+xy@b.com</td>
133+
<td style="border: 1px solid black;">ab+xy</td>
134+
<td style="border: 1px solid black;">ab</td>
135+
<td style="border: 1px solid black;">b.com</td>
136+
<td style="border: 1px solid black;">b.com</td>
137+
<td style="border: 1px solid black;">ab@b.com</td>
138+
</tr>
139+
<tr>
140+
<td style="border: 1px solid black;">a.b@b.com</td>
141+
<td style="border: 1px solid black;">a.b</td>
142+
<td style="border: 1px solid black;">ab</td>
143+
<td style="border: 1px solid black;">b.com</td>
144+
<td style="border: 1px solid black;">b.com</td>
145+
<td style="border: 1px solid black;">ab@b.com</td>
146+
</tr>
147+
</tbody>
148+
</table>
149+
150+
<p>Unique emails are [<code>&quot;a@b.com&quot;</code>, <code>&quot;ab@b.com&quot;</code>]. Thus, the answer is 2.</p>
151+
</div>
152+
153+
<p><strong class="example">Example 3:</strong></p>
154+
155+
<div class="example-block">
156+
<p><strong>Input:</strong> <span class="example-io">emails = [&quot;a.b+c.d+e@DoMain.com&quot;, &quot;ab+xyz@domain.com&quot;, &quot;ab@domain.com&quot;]</span></p>
157+
158+
<p><strong>Output:</strong> <span class="example-io">1</span></p>
159+
160+
<p><strong>Explanation:</strong></p>
161+
162+
<table style="border: 1px solid black;">
163+
<thead>
164+
<tr>
165+
<th style="border: 1px solid black;">Email</th>
166+
<th style="border: 1px solid black;">Local</th>
167+
<th style="border: 1px solid black;">Normalized Local</th>
168+
<th style="border: 1px solid black;">Domain</th>
169+
<th style="border: 1px solid black;">Normalized Domain</th>
170+
<th style="border: 1px solid black;">Final Email</th>
171+
</tr>
172+
</thead>
173+
<tbody>
174+
<tr>
175+
<td style="border: 1px solid black;">a.b+c.d+e@DoMain.com</td>
176+
<td style="border: 1px solid black;">a.b+c.d+e</td>
177+
<td style="border: 1px solid black;">ab</td>
178+
<td style="border: 1px solid black;">DoMain.com</td>
179+
<td style="border: 1px solid black;">domain.com</td>
180+
<td style="border: 1px solid black;">ab@domain.com</td>
181+
</tr>
182+
<tr>
183+
<td style="border: 1px solid black;">ab+xyz@domain.com</td>
184+
<td style="border: 1px solid black;">ab+xyz</td>
185+
<td style="border: 1px solid black;">ab</td>
186+
<td style="border: 1px solid black;">domain.com</td>
187+
<td style="border: 1px solid black;">domain.com</td>
188+
<td style="border: 1px solid black;">ab@domain.com</td>
189+
</tr>
190+
<tr>
191+
<td style="border: 1px solid black;">ab@domain.com</td>
192+
<td style="border: 1px solid black;">ab</td>
193+
<td style="border: 1px solid black;">ab</td>
194+
<td style="border: 1px solid black;">domain.com</td>
195+
<td style="border: 1px solid black;">domain.com</td>
196+
<td style="border: 1px solid black;">ab@domain.com</td>
197+
</tr>
198+
</tbody>
199+
</table>
200+
201+
<p>All emails normalize to <code>&quot;ab@domain.com&quot;</code>. Thus, the answer is 1.</p>
202+
</div>
203+
204+
<p>&nbsp;</p>
205+
<p><strong>Constraints:</strong></p>
206+
207+
<ul>
208+
<li><code>1 &lt;= emails.length &lt;= 1000</code></li>
209+
<li><code>1 &lt;= emails[i].length &lt;= 100</code></li>
210+
<li><code>emails[i]</code> consists of lowercase and uppercase English letters, digits, and the characters <code>&#39;.&#39;</code>, <code>&#39;+&#39;</code>, and <code>&#39;@&#39;</code>.</li>
211+
<li>Each <code>emails[i]</code> contains <strong>exactly</strong> one <code>&#39;@&#39;</code> character.</li>
212+
<li>All local and domain names are non-empty; local names do not start with <code>&#39;+&#39;</code>.</li>
213+
<li>Domain names end with the <code>&quot;.com&quot;</code> suffix and contain at least one character before <code>&quot;.com&quot;</code>.</li>
214+
</ul>
215+
216+
<!-- description:end -->
217+
218+
## 解法
219+
220+
<!-- solution:start -->
221+
222+
### 方法一:哈希表
223+
224+
我们可以使用一个哈希表 $\textit{st}$ 来存储每个邮箱地址的规范化结果。对于每个邮箱地址,我们按照题目要求进行规范化处理:
225+
226+
- 将邮箱地址分为本地名和域名两部分。
227+
- 对于本地名,去掉所有的点 `.`,并且如果存在加号 `+`,则去掉加号及其后面的部分。最后将本地名转换为小写。
228+
- 对于域名,将其转换为小写。
229+
- 将规范化后的本地名和域名拼接起来,得到规范化后的邮箱地址,并将其加入哈希表 $\textit{st}$ 中。
230+
231+
最后,哈希表 $\textit{st}$ 中的元素个数即为唯一邮箱组的数量。
232+
233+
时间复杂度 $O(n \cdot m)$,其中 $n$ 和 $m$ 分别是邮箱地址的数量和每个邮箱地址的平均长度。空间复杂度 $O(n \cdot m)$,最坏情况下所有邮箱地址都不同。
234+
235+
<!-- tabs:start -->
236+
237+
#### Python3
238+
239+
```python
240+
class Solution:
241+
def uniqueEmailGroups(self, emails: list[str]) -> int:
242+
st = set()
243+
for email in emails:
244+
local, domain = email.split("@")
245+
local = local.split("+")[0].replace(".", "").lower()
246+
domain = domain.lower()
247+
normalized = local + domain
248+
st.add(normalized)
249+
return len(st)
250+
```
251+
252+
#### Java
253+
254+
```java
255+
class Solution {
256+
public int uniqueEmailGroups(String[] emails) {
257+
Set<String> st = new HashSet<>();
258+
259+
for (String email : emails) {
260+
String[] parts = email.split("@");
261+
String local = parts[0];
262+
String domain = parts[1];
263+
264+
int plusIndex = local.indexOf('+');
265+
if (plusIndex != -1) {
266+
local = local.substring(0, plusIndex);
267+
}
268+
269+
local = local.replace(".", "").toLowerCase();
270+
domain = domain.toLowerCase();
271+
272+
String normalized = local + domain;
273+
st.add(normalized);
274+
}
275+
276+
return st.size();
277+
}
278+
}
279+
```
280+
281+
#### C++
282+
283+
```cpp
284+
class Solution {
285+
public:
286+
int uniqueEmailGroups(vector<string>& emails) {
287+
unordered_set<string> st;
288+
289+
for (auto& email : emails) {
290+
int atPos = email.find('@');
291+
string local = email.substr(0, atPos);
292+
string domain = email.substr(atPos + 1);
293+
294+
int plusPos = local.find('+');
295+
if (plusPos != string::npos) {
296+
local = local.substr(0, plusPos);
297+
}
298+
299+
string cleaned;
300+
for (char c : local) {
301+
if (c != '.') {
302+
cleaned += tolower(c);
303+
}
304+
}
305+
306+
for (char& c : domain) {
307+
c = tolower(c);
308+
}
309+
310+
st.insert(cleaned + domain);
311+
}
312+
313+
return st.size();
314+
}
315+
};
316+
```
317+
318+
#### Go
319+
320+
```go
321+
func uniqueEmailGroups(emails []string) int {
322+
st := make(map[string]struct{})
323+
324+
for _, email := range emails {
325+
parts := strings.Split(email, "@")
326+
local := parts[0]
327+
domain := parts[1]
328+
329+
if idx := strings.Index(local, "+"); idx != -1 {
330+
local = local[:idx]
331+
}
332+
333+
local = strings.ReplaceAll(local, ".", "")
334+
local = strings.ToLower(local)
335+
domain = strings.ToLower(domain)
336+
337+
normalized := local + domain
338+
st[normalized] = struct{}{}
339+
}
340+
341+
return len(st)
342+
}
343+
```
344+
345+
#### TypeScript
346+
347+
```ts
348+
function uniqueEmailGroups(emails: string[]): number {
349+
const st = new Set<string>();
350+
351+
for (const email of emails) {
352+
let [local, domain] = email.split('@');
353+
local = local.split('+')[0].replace(/\./g, '').toLowerCase();
354+
domain = domain.toLowerCase();
355+
356+
const normalized = local + domain;
357+
st.add(normalized);
358+
}
359+
360+
return st.size;
361+
}
362+
```
363+
364+
<!-- tabs:end -->
365+
366+
<!-- solution:end -->
367+
368+
<!-- problem:end -->

0 commit comments

Comments
 (0)