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.
  • 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:

Email 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:

Email 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:

Email 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 <= 1000
  • 1 <= emails[i].length <= 100
  • emails[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;
    }
    
    

All Problems

All Solutions