-
Notifications
You must be signed in to change notification settings - Fork 0
929. Unique Email Addresses #14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| # 問題 | ||
| https://leetcode.com/problems/unique-email-addresses | ||
|
|
||
| メールアドレスは `@` で区切られた local name と domain name からなる。local name には次のルールが適用される: | ||
|
|
||
| - `.` は無視される(`alice.z@leetcode.com` と `alicez@leetcode.com` は同じ宛先) | ||
| - 最初の `+` 以降は無視される(`m.y+name@email.com` は `my@email.com` に届く) | ||
|
|
||
| domain name にはこれらのルールは適用されない。メールアドレスの配列 `emails` が与えられたとき、実際にメールを受け取る一意なアドレスの数を返す。 | ||
|
|
||
| - 例1: `["test.email+alex@leetcode.com","test.e.mail+bob.cathy@leetcode.com","testemail+david@lee.tcode.com"]` → `2` | ||
| - 例2: `["a@leetcode.com","b@leetcode.com","c@leetcode.com"]` → `3` | ||
| - 制約: `1 <= emails.length <= 100`、`1 <= emails[i].length <= 100`、使用文字は小文字英字と `'+'` `'.'` `'@'` のみ、各 `emails[i]` はちょうど1つの `@` を含む、local name と domain name は空でない、local name は `+` で始まらない、domain name は `.com` で終わる | ||
|
|
||
| # 前提 | ||
| - 答えを見ずに考えて、5分考えて分からなかったら答えを見てください。答えを見て理解したと思ったら、答えを隠して書いてください。筆が進まず5分迷ったら答えを見てください。そして、見ちゃったら一回全部消してやり直しです。答えを送信して、正解になったら、まずは一段階目です。 | ||
| - 次にコードを読みやすくするようにできるだけ整えましょう。これで動くコードになったら二段階目です。 | ||
| - そしたらまた全部消しましょう。今度は、時間を測りながら、もう一回、書きましょう。書いてアクセプトされたら文字を消してもう一回書きましょう。これを10分以内に一回もエラーを出さずに書ける状態になるまで続けてください。3回続けてそれができたらその問題はひとまず丸です。 | ||
| --- | ||
|
|
||
| # 1回目 | ||
| ```go | ||
| // 方針.invalidなものも含まれると考える. | ||
| // 各メールアドレスに対して,`@` で分割する.localname側のdotを除去&`+`以降を削除する(`+`で分割し,leftのみ利用する) | ||
| // memo: 末尾の`.`の扱いが問題文から読み取れない.ドメインネームについても同様に末尾に`.`がつくようなドメインをinvalidとするかは読み取れない. | ||
| // 読み取れないものは一度無視して実装してみる | ||
|
|
||
| import "strings" | ||
|
|
||
| func numUniqueEmails(emails []string) int { | ||
| uniqueEmails := map[string]bool{} | ||
| for _, email := range emails { | ||
| splited := strings.Split(email, "@") | ||
| localname, domain := splited[0], splited[1] | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 自分なら localName とすると思います。
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. こちらもGoの慣習から外れた命名でした.ご指摘ありがとうございます |
||
|
|
||
| localname = strings.ReplaceAll(localname, ".", "") | ||
| localname = strings.Split(localname, "+")[0] | ||
|
|
||
| canonical := fmt.Sprintf("%s@%s", localname, domain) | ||
| uniqueEmails[canonical] = true | ||
| } | ||
|
|
||
| return len(uniqueEmails) | ||
| } | ||
| ``` | ||
| - 単純だからか,わりと初回からわかりやすくかけたのではないか. | ||
| - 実行時間と時間計算量の見積もり | ||
| - emailsの数がN,emailそれぞれの長さをMとすると,O(NM) | ||
| - strings.ReplaceAllとstrings.Splitは文字列走査をするはずなので,O(M) と見積もった | ||
| - 毎秒10^8ステップ程度の処理ができるとする. emails.length <= 100, emails[i].length <= 100となっているので, | ||
| - (N * M) / 10^8 = 100 * 100 / 10^8 = 10^-4 = 0.1ms程度 | ||
| - 必要メモリと空間計算量の見積もり: | ||
| - N回のループの中で,都度変数を確保している分は定数倍 | ||
| - uniqueEmails は O(N)のサイズがあればよい | ||
| - ひとつひとつのエントリはO(M) | ||
| - よって全体としてはO(NM) | ||
| - 1文字は1byteとする. emails.length <= 100, emails[i].length <= 100となっているので, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. もう少し丁寧に書いてもいいかなと思いました。
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. これはその通りですね |
||
| - 100 * 100 * 1 = 10^4 byte = 10kbyte | ||
| - hashtableはメモリを余分に必要とするので,倍として20KB程度 | ||
| - reference | ||
| - https://cs.opensource.google/go/go/+/refs/tags/go1.26.4:src/strings/strings.go;l=361 | ||
| - https://cs.opensource.google/go/go/+/refs/tags/go1.26.4:src/strings/strings.go;l=1180 | ||
|
|
||
| # 2回目 | ||
| ```go | ||
| import "strings" | ||
|
|
||
| func numUniqueEmails(emails []string) int { | ||
| uniqueEmails := map[string]bool{} | ||
| for _, email := range emails { | ||
| localname, domain, _ := strings.Cut(email, "@") | ||
|
|
||
| localname = strings.ReplaceAll(localname, ".", "") | ||
| localname, _, _ = strings.Cut(localname, "+") | ||
|
|
||
| canonical := fmt.Sprintf("%s@%s", localname, domain) | ||
| uniqueEmails[canonical] = true | ||
| } | ||
|
|
||
| return len(uniqueEmails) | ||
| } | ||
|
|
||
| ``` | ||
| - LLMより,`strings.Cut` | ||
| という関数を教えてもらったのでこれのバージョンを書いてみたが,別にわかりやすくもないような... | ||
| - https://pkg.go.dev/strings#Cut | ||
| - もっと実務的なvalidationが必要になる場合には `net/mail.ParseAddress` を利用するのがよさそう | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 言及されているように、今の制約ならどうか、その制約が変わったらどうかを考えるのは大事だと思います。
これでいうと、以下のようなものが背景知識になるかと思います。 ご覧になっていなければ、コメント集を見るのもよいと思います。
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. コメント集を確認できてなかったので確認します ありがとうございます!
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. みました. ステートマシン 言及されているあたりを思い浮かべながら,それを伝える訓練としてPRを作れるとよさそうですね (返信不要です) |
||
|
|
||
| # 3回目 | ||
| ```go | ||
| import "strings" | ||
| import "fmt" | ||
|
|
||
| func numUniqueEmails(emails []string) int { | ||
| uniqueEmails := map[string]bool{} | ||
| for _, email := range emails { | ||
| splited := strings.Split(email, "@") | ||
| localname, domain := splited[0], splited[1] | ||
|
|
||
| localname = strings.ReplaceAll(localname, ".", "") | ||
| localname = strings.Split(localname, "+")[0] | ||
|
|
||
| canonical := fmt.Sprintf("%s@%s", localname, domain) | ||
| uniqueEmails[canonical] = true | ||
| } | ||
| return len(uniqueEmails) | ||
| } | ||
| ``` | ||
| - 結局初回のコードを3回繰り返す | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
問題文中で local name と domain name となっているにもかかわらず、 localname と domain と name が付いているのといないのとで統一されていない点に違和感を感じました。どちらかに統一するとよいと思います。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
たしかに,統一感のない命名でした.ご指摘ありがとうございます