Welcome to Subscribe On Youtube
3860. Unique Email Groups 🔒
Description
You are given an array of strings emails, where each string is a valid email address.
Two email addresses belong to the same group if both their normalized local names and normalized domain names are identical.
The normalization rules are as follows:
- The local name is the part before the
'@'symbol.- Ignore all dots
'.'. - Ignore everything after the first
'+', if present. - Convert to lowercase.
- Ignore all dots
- The domain name is the part after the
'@'symbol.- Convert to lowercase.
Return an integer denoting the number of unique email groups after normalization.
Example 1:
Input: emails = ["test.email+alex@leetcode.com", "test.e.mail+bob.cathy@leetcode.com", "testemail+david@lee.tcode.com"]
Output: 2
Explanation:
| Local | Normalized Local | Domain | Normalized Domain | Final Email | |
|---|---|---|---|---|---|
| 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 |
Unique emails are ["testemail@leetcode.com", "testemail@lee.tcode.com"]. Thus, the answer is 2.
Example 2:
Input: emails = ["A@B.com", "a@b.com", "ab+xy@b.com", "a.b@b.com"]
Output: 2
Explanation:
| Local | Normalized Local | Domain | Normalized Domain | Final Email | |
|---|---|---|---|---|---|
| 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 |
Unique emails are ["a@b.com", "ab@b.com"]. Thus, the answer is 2.
Example 3:
Input: emails = ["a.b+c.d+e@DoMain.com", "ab+xyz@domain.com", "ab@domain.com"]
Output: 1
Explanation:
| Local | Normalized Local | Domain | Normalized Domain | Final Email | |
|---|---|---|---|---|---|
| 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 |
All emails normalize to "ab@domain.com". Thus, the answer is 1.
Constraints:
1 <= emails.length <= 10001 <= emails[i].length <= 100emails[i]consists of lowercase and uppercase English letters, digits, and the characters'.','+', and'@'.- Each
emails[i]contains exactly one'@'character. - All local and domain names are non-empty; local names do not start with
'+'. - Domain names end with the
".com"suffix and contain at least one character before".com".
Solutions
Solution 1: Hash Table
We can use a hash set $\textit{st}$ to store the normalized result of each email address. For each email address, we normalize it according to the problem requirements:
- Split the email address into a local name and a domain name.
- For the local name, remove all dots
., and if a plus sign+exists, remove the plus sign and everything after it. Then convert the local name to lowercase. - For the domain name, convert it to lowercase.
- Concatenate the normalized local name and domain name to obtain the normalized email address, and add it to the hash set $\textit{st}$.
Finally, the number of elements in the hash set $\textit{st}$ is the number of unique email groups.
The time complexity is $O(n \cdot m)$, where $n$ and $m$ are the number of email addresses and the average length of each email address, respectively. The space complexity is $O(n \cdot m)$, in the worst case where all email addresses are distinct.
-
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(); } } -
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(); } }; -
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) -
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) } -
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; }