# Question

Formatted question description: https://leetcode.ca/all/929.html

Every email consists of a local name and a domain name, separated by the @ sign.
For example, in alice@leetcode.com, alice is the local name, and leetcode.com is the domain name.

Besides lowercase letters, these emails may contain '.'s or '+'s.

If you add periods ('.') between some characters in the local name part of an email address, mail sent there will be forwarded to the same address without dots in the local name.  For example, "alice.z@leetcode.com" and "alicez@leetcode.com" forward to the same email address.  (Note that this rule does not apply for domain names.)

If you add a plus ('+') in the local name, everything after the first plus sign will be ignored. This allows certain emails to be filtered, for example m.y+name@email.com will be forwarded to my@email.com.  (Again, this rule does not apply for domain names.)

It is possible to use both of these rules at the same time.

Given a list of emails, we send one email to each address in the list.  How many different addresses actually receive mails?

Example 1:

Input: ["test.email+alex@leetcode.com","test.e.mail+bob.cathy@leetcode.com","testemail+david@lee.tcode.com"]
Output: 2
Explanation: "testemail@leetcode.com" and "testemail@lee.tcode.com" actually receive mails
Note:

1 <= emails[i].length <= 100
1 <= emails.length <= 100
Each emails[i] contains exactly one '@' character.
All local and domain names are non-empty.



# Algorithm

This question is about mail. There may be two special symbols in the mail name, dot and plus. For dots, ignore everything behind it. Now ask us how many Different mailboxes. Without too many skills, just traverse all the characters directly, skip directly when encountering a dot, and break directly when encountering a’+’ or’@’. Note that there is actually a pit, even in the domain name, and this point cannot be ignored, so extract all the domain names after’@’ and connect them to the account that has been processed before and put them together In HashSet, using its de-duplication feature, the final remaining number is what is required, see the code as follows:

# Code

C++

class Solution {
public:
int numUniqueEmails(vector<string>& emails) {
unordered_set<string> st;
for (string email : emails) {
string name;
for (char c : email) {
if (c == '.') continue;
if (c == '+' || c == '@') break;
name.push_back(c);
}
name += email.substr(email.find('@'));
st.insert(name);
}
return st.size();
}
};



Java

• import java.util.HashSet;
import java.util.Set;

public static void main(String[] args) {
Solution s = out.new Solution();

String[] input = new String[]{
"test.email+alex@leetcode.com",
"test.e.mail+bob.cathy@leetcode.com",
"testemail+david@lee.tcode.com"
};

System.out.println(s.numUniqueEmails(input));
}

class Solution {
public int numUniqueEmails(String[] emails) {
if (emails == null || emails.length == 0) {
return 0;
}

Set<String> emailSet = new HashSet<>();

for (String each: emails) {
process(each, emailSet);
}

return emailSet.size();
}

private void process (String email, Set<String> emailSet) {
int atIndex = email.indexOf('@');
String localName = email.substring(0, atIndex);

// truncate all after '+'
int plusIndex = !localName.contains("+") ? atIndex: localName.indexOf("+");
String localNameTruncated = localName.substring(0, plusIndex);
// remove all '.'
String resultLocalName = localNameTruncated.replace(".","");

emailSet.add(resultLocalName + "@" + email.substring(atIndex + 1));
}
}
}

• // OJ: hhttps://leetcode.com/problems/unique-email-addresses/
// Time: O(N)
// Space: O(N)
class Solution {
private:
string normalize(string &email) {
string ans;
int i = 0;
for (; email[i] != '@'; ++i) {
if (isalpha(email[i])) ans += email[i];
if (email[i] == '+') break;
}
while (email[i] != '@') ++i;
return ans + email.substr(i);
}
public:
int numUniqueEmails(vector<string>& emails) {
unordered_set<string> s;
for (auto email : emails) {
s.insert(normalize(email));
}
return s.size();
}
};

• class Solution(object):
def numUniqueEmails(self, emails):
"""
:type emails: List[str]
:rtype: int
"""
eset = set()
for email in emails:
simper = self.simpifyEmail(email)
return len(eset)

def simpifyEmail(self, email):
local, domain = email.split("@")
local = local.replace('.', '')
plus_i = local.find('+')
if plus_i != -1:
local = local[:plus_i]
return local + "@" + domain


Java

• class Solution {
public int numUniqueEmails(String[] emails) {
Set<String> emailsSet = new HashSet<String>();
for (String email : emails) {
int atIndex = email.indexOf("@");
String localName = email.substring(0, atIndex);
String domainName = email.substring(atIndex);
localName = localName.replaceAll("\\.", "");
if (localName.indexOf('+') >= 0)
localName = localName.substring(0, localName.indexOf('+'));
String actualEmail = localName + domainName;
}
return emailsSet.size();
}
}

• // OJ: hhttps://leetcode.com/problems/unique-email-addresses/
// Time: O(N)
// Space: O(N)
class Solution {
private:
string normalize(string &email) {
string ans;
int i = 0;
for (; email[i] != '@'; ++i) {
if (isalpha(email[i])) ans += email[i];
if (email[i] == '+') break;
}
while (email[i] != '@') ++i;
return ans + email.substr(i);
}
public:
int numUniqueEmails(vector<string>& emails) {
unordered_set<string> s;
for (auto email : emails) {
s.insert(normalize(email));
}
return s.size();
}
};

• class Solution(object):
def numUniqueEmails(self, emails):
"""
:type emails: List[str]
:rtype: int
"""
eset = set()
for email in emails:
simper = self.simpifyEmail(email)
return len(eset)

def simpifyEmail(self, email):
local, domain = email.split("@")
local = local.replace('.', '')
plus_i = local.find('+')
if plus_i != -1:
local = local[:plus_i]
return local + "@" + domain