Easy

题目描述

每个有效的电子邮件地址都由一个本地名和一个域名组成,用 ‘@’ 符号分隔。除了小写字母,电子邮件可能包含一个或多个 ‘.’ 或 ‘+’。

例如,在 “alice@leetcode.com” 中,“alice” 是本地名,“leetcode.com” 是域名。

如果在电子邮件地址的本地名部分中的某些字符之间添加句点 ‘.’,发送到那里的邮件将被转发到本地名中没有点的相同地址。注意,此规则不适用于域名。

例如,“alice.z@leetcode.com” 和 “alicez@leetcode.com” 转发到相同的电子邮件地址。

如果在本地名中添加加号 ‘+’,加号后的所有内容都将被忽略。这允许过滤某些电子邮件。注意,此规则不适用于域名。

例如,“m.y+name@email.com” 将被转发到 “my@email.com”。

可以同时使用这两个规则。

给定一个字符串数组 emails,我们会向 emails[i] 发送一封电子邮件。返回实际收到邮件的不同地址数量。

示例 1:

输入: emails = ["test.email+alex@leetcode.com","test.e.mail+bob.cathy@leetcode.com","testemail+david@lee.tcode.com"]
输出: 2
解释: "testemail@leetcode.com" 和 "testemail@lee.tcode.com" 实际收到邮件。

示例 2:

输入: emails = ["a@leetcode.com","b@leetcode.com","c@leetcode.com"]
输出: 3

提示:

  • 1 <= emails.length <= 100
  • 1 <= emails[i].length <= 100
  • emails[i] 由小写英文字母、’+’, ‘.’ 和 ‘@’ 组成
  • 每个 emails[i] 都包含一个 ‘@’ 字符
  • 所有本地名和域名都非空
  • 本地名不以 ‘+’ 字符开头
  • 域名以 “.com” 后缀结尾

解题思路

解题思路

这是一道字符串处理题目,需要我们理解电子邮件地址的规范化规则:

  1. 分离本地名和域名:以 ‘@’ 为分隔符将邮件地址分为两部分
  2. 处理本地名规则
    • 遇到 ‘+’ 时,忽略后面所有字符
    • 移除所有的 ‘.’ 字符
  3. 保持域名不变:域名部分不应用任何规则
  4. 统计唯一地址:使用哈希集合存储规范化后的地址

算法步骤

  1. 遍历每个邮件地址
  2. 找到 ‘@’ 的位置,分离本地名和域名
  3. 对本地名进行规范化处理:
    • 如果遇到 ‘+’,截取到 ‘+’ 之前的部分
    • 移除所有的 ‘.’ 字符
  4. 将规范化后的地址添加到集合中
  5. 返回集合的大小

时间复杂度为 O(nm),其中 n 是邮件数量,m 是平均邮件长度。空间复杂度为 O(nm),用于存储规范化后的邮件地址。

代码实现

class Solution {
public:
    int numUniqueEmails(vector<string>& emails) {
        unordered_set<string> uniqueEmails;
        
        for (const string& email : emails) {
            int atPos = email.find('@');
            string localName = email.substr(0, atPos);
            string domainName = email.substr(atPos);
            
            // 处理本地名
            string processedLocal = "";
            for (char c : localName) {
                if (c == '+') {
                    break; // 忽略+后面的所有字符
                }
                if (c != '.') {
                    processedLocal += c; // 忽略句点
                }
            }
            
            uniqueEmails.insert(processedLocal + domainName);
        }
        
        return uniqueEmails.size();
    }
};
class Solution:
    def numUniqueEmails(self, emails: List[str]) -> int:
        unique_emails = set()
        
        for email in emails:
            local_name, domain_name = email.split('@')
            
            # 处理本地名
            # 先处理+号,忽略+后面的内容
            if '+' in local_name:
                local_name = local_name[:local_name.index('+')]
            
            # 移除所有的句点
            local_name = local_name.replace('.', '')
            
            unique_emails.add(local_name + '@' + domain_name)
        
        return len(unique_emails)
public class Solution {
    public int NumUniqueEmails(string[] emails) {
        HashSet<string> uniqueEmails = new HashSet<string>();
        
        foreach (string email in emails) {
            int atIndex = email.IndexOf('@');
            string localName = email.Substring(0, atIndex);
            string domainName = email.Substring(atIndex);
            
            // 处理本地名
            StringBuilder processedLocal = new StringBuilder();
            foreach (char c in localName) {
                if (c == '+') {
                    break; // 忽略+后面的所有字符
                }
                if (c != '.') {
                    processedLocal.Append(c); // 忽略句点
                }
            }
            
            uniqueEmails.Add(processedLocal.ToString() + domainName);
        }
        
        return uniqueEmails.Count;
    }
}
var numUniqueEmails = function(emails) {
    const uniqueEmails = new Set();
    
    for (let email of emails) {
        const [local, domain] = email.split('@');
        let cleanLocal = local.split('+')[0].replace(/\./g, '');
        uniqueEmails.add(cleanLocal + '@' + domain);
    }
    
    return uniqueEmails.size;
};

复杂度分析

复杂度类型复杂度说明
时间复杂度O(n × m)n 是邮件数量,m 是平均邮件长度,需要遍历每个邮件的每个字符
空间复杂度O(n × m)最坏情况下所有邮件地址都不同,需要存储 n 个长度为 m 的字符串