# LeetCode Solution, Easy, 929. Unique Email Addresses

# [929. Unique Email Addresses](https://leetcode.com/problems/unique-email-addresses/)

### 題目敘述

Every **valid email** consists of a **local name** and a **domain name**, separated by the `'@'` sign. Besides lowercase letters, the email may contain one or more `'.'` or `'+'`.

-   For example, in `"alice@leetcode.com"`, `"alice"` is the **local name**, and `"leetcode.com"` is the **domain name**.

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. Note that this rule **does not apply** to **domain names**.

-   For example, `"alice.z@leetcode.com"` and `"alicez@leetcode.com"` forward to the same email address.

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. Note that this rule **does not apply** to **domain names**.

-   For example, `"m.y+name@email.com"` will be forwarded to `"my@email.com"`.

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

Given an array of strings `emails` where we send one email to each `email[i]`, return _the number of different addresses that actually receive mails_.

**Example 1:**

    Input: emails = ["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.

**Example 2:**

    Input: emails = ["a@leetcode.com","b@leetcode.com","c@leetcode.com"]
    Output: 3

**Constraints:**

-   `1 <= emails.length <= 100`
-   `1 <= emails[i].length <= 100`
-   `email[i]` consist of lowercase English letters, `'+'`, `'.'` and `'@'`.
-   Each `emails[i]` contains exactly one `'@'` character.
-   All local and domain names are non-empty.
-   Local names do not start with a `'+'` character.

#### 題目翻譯

此題目會給一個陣列，其中的元素都是 Email 的資料。以 `@` 為區別，前面是 local name 後面是 domain name。在 local name 的部分有兩個條件。當包含 `.` 的部分會忽略，例如 `a.b` 相當於 `ab`。而當包含 `+` 的時候，會忽略連接的字，例如 `a+b` 相當於 `a`。而在這兩個條件的情況下，要去判斷有幾個不重複的 Email。

### 解法解析

這題的解法是很簡單的，使用一個迴圈基本上就可以處理。Time complexity：`O(n)`，Space complexity：`O(1)`。
這題主要 focus 在迴圈中處理 local name 的條件判斷，清除 `.` 或 `+` 之後跟 domain name 重組回 email，後直接存在 `Set` 中做去重的處理。最後判斷 `Set` 的大小就可以了。

#### 程式範例

##### Python

```python
class Solution:
    def numUniqueEmails(self, emails: List[str]) -> int:
        seen = set()
        for email in emails:
            name, domain = email.split('@')
            local = name.split('+')[0].replace('.', '')
            seen.add(f'{local}@{domain}')
        return len(seen)
```

##### JavaScript

```javascript
/**
 * @param {string[]} emails
 * @return {number}
 */
var numUniqueEmails = function(emails) {
    return new Set(
        emails.map(
            (mail) =>
                `${mail.split('@')[0].replace(/\+.*$|\./g, '')}@${
                    mail.split('@')[1]
                }`
        )
    ).size;
};
```

##### Go

```go
func numUniqueEmails(emails []string) int {
	m := map[string]bool{}
	for _, e := range emails {
		a := strings.Split(e, "@")
		l := strings.Split(a[0], "+")[0]
		l = strings.ReplaceAll(l, ".", "")
		m[fmt.Sprintf("%s@%s", l, a[1])] = true
	}
	return len(m)
}
```

##### Swift

```swift
class Solution {
    func numUniqueEmails(_ emails: [String]) -> Int {
        guard emails.count > 0 else { return 0 }
        var resultSet = Set<String>()

        for email in emails {
            let seperated = email.split(separator: "@")
            let local = seperated[0], validDomain = seperated[1]
            var validLocal = String()

            for char in local where char != "." {
                guard char != "+" else { break }
                validLocal.append(char)
            }

            let validFormat = validLocal + "@" + validDomain
            resultSet.insert(String(validFormat))
        }
        return resultSet.count
    }
}
```

##### Kotlin

```kotlin
class Solution {
    fun numUniqueEmails(emails: Array<String>): Int {
        return emails
                .map {
                    val localName =
                            it.substringBefore('@').filter { c -> c != '.' }.substringBefore('+')
                    val address = it.substringAfter('@')
                    "$localName@$address"
                }
                .toSet()
                .size
    }
}
```
