JavaScript 100% | 68ms  Very Simple Set Solution
\n\nPosting solutions to dailies.\n\n\nvar numUniqueEmails = function(emails) {\n  const res = new Set();\n  for (let email of emails) {\n    if (email.includes
![image](https://assets.leetcode.com/users/images/9fd56a9d-0d2c-45aa-a6cb-e73ae82c7fe0_1632762725.68751.png)\n\nPosting solutions to dailies.\n\n```\nvar numUniqueEmails = function(emails) {\n  const res = new Set();\n  for (let email of emails) {\n    if (email.includes(\'+\')) {\n      let pIdx = email.indexOf(\'+\')\n      let aIdx = email.indexOf(\'@\')\n      email = email.substr(0, pIdx) + email.substr(aIdx)\n    }\n    email = email.split(\'@\');\n    email[0].includes(\'.\') && \n      (email[0] = email[0].replace(/[.]/g, \'\'))\n    email = email.join(\'@\')\n    res.add(email)\n  }\n  return res.size\n};\n```\n\nNote:  You can also do\n```\n    let [local, domain] = email.split(\'@\');\n    local = local.replace(/[.]/g, \'\')\n    res.add(local + \'@\' + domain)\n```\nThis might be a little more readable / easier to work with in an actual code base.  Here on LC, it just adds runtime and space though.  That said, I do like destructuring for readability in cases like this.\n\nHere is an alternate string method only version without .split().  I wanted to see if the runtime was faster, it\'s about the same though.\n```\nvar numUniqueEmails = function(emails) {\n  const res = new Set();\n  for (let email of emails) {\n    if (email.includes(\'+\')) {\n      const pIdx = email.indexOf(\'+\')\n      const aIdx = email.indexOf(\'@\')\n      email = email.substr(0, pIdx) + email.substr(aIdx)\n    }\n    let splitIdx = email.indexOf(\'@\')\n    email = email.substr(0,splitIdx).replace(/[.]/g, \'\') + email.substr(splitIdx)\n    res.add(email)\n  }\n  return res.size\n};\n```\n\nOne last version, because I thought getting rid of the O(n) .indexOf calls would speed it up markedly.  Performance improvement was negligible though.  It still gets 100%, but 72ms was the best I got in 5x runs.  Technically, I do believe this algorithm does the least amount of work though.  One O(n) for each email to get necessary indexes, another O(local.length) for the replace. O(numEmails * localDomainLength) for all of these solutions.  This one only has to loop through local domain twice though, others do it 3+ times.  Was a small improvement experiment, and completely unnecessary optimization since the results were negligible and readability suffered dramatically.\n\n```\nvar numUniqueEmails = function(emails) {\n  const res = new Set();\n  for (let email of emails) {\n    let pIdx, aIdx, hasP = false;\n    for (let i = 0; i < email.length; i++) {\n      if (!pIdx && email[i] === \'+\') pIdx = i;\n      else if (email[i] === \'@\') {\n        aIdx = i;\n        if (!pIdx) pIdx = i;\n        break;\n      } else if (email[i] === \'.\') hasP = true;\n    }\n    if (pIdx !== aIdx) email = email.substr(0, pIdx) + email.substr(aIdx)\n    if (hasP) email = email.substr(0, pIdx).replace(/[.]/g, \'\') + email.substr(pIdx)\n    res.add(email)\n  }\n  return res.size\n};\n```\n\nI lied - last, last version.  Here we just simply build up the local and as soon as we reach the @, we add on the rest and put it in the set.\n\n```\nconst numUniqueEmails = emails => {\n  const res = new Set();\n  for (let email of emails) {\n    let formated = \'\';\n    for (let i = 0, char = email[i], afP;\n         i < email.length; char = email[++i]) {\n      if (char === \'@\') {\n        formated += email.substr(i);\n        break;\n      }\n      if (char === \'+\') afP = true;\n      if (afP || char === \'.\') continue;\n      formated += char\n    }\n    res.add(formated);\n  }\n  return res.size;\n}\n```\n\n![image](https://assets.leetcode.com/users/images/783d5532-9323-4ad3-8f52-9e1019df68e6_1632762735.7302983.png)\n
['JavaScript']