929. unique email addresses#13
Conversation
| } | ||
| return seen.size(); | ||
| } | ||
| }; |
There was a problem hiding this comment.
後学のため、問題文+例+制約を読んでから、どのように道筋を立てたか教えて頂けないでしょうか?
図にする。プロセスの整理をする。なんでも良いです。
There was a problem hiding this comment.
@Apo-Matchbox
コメントありがとうございます。この問題の場合ですと、
- 結局入力のemailたちを送り先が同じものを同一視した場合に送り先はいくつあるか?と言い換えられるので、各emailを正規化したあとstd::set (or std::unordered_set)に入れて最後に個数を返せばよさそうだな。
- 一つのemailを正規化するには、@の前後で分割して、local_nameの部分は.を取り除き+以降を無視してdomain_nameとくっつければよさそう。文字列のライブラリを使えばすぐできそうだが、それを手でやる趣旨の出題だと思う。
- 2を実現するにはemailを前から見て行って条件を満たすように文字を付け加えればよい。local_nameとdomain_nameではロジックがちょっと違うからそれぞれwhileループで加えていこう。(まとめて書くこともできるがやや複雑になる)
- whileのループ中で+まで到達したかどうかはフラグで管理して条件分岐すればよい。ループに関してはコメント集で「引継ぎ」で見ると良いかもしれませんhttps://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/edit?tab=t.0#heading=h.xzxd7jwvkwc5
- 正規化の手順を振り返る。本質的に正規化をするにはemailの各文字を見るほかないのでO(n)以上に効率がよくなることはなさそう。
- 1について正規化されたemailを分類するには比較をしないといけないのでsetに入れる以上に効率的にはならなさそう。
といった思考プロセスだったかと思います。
まとめると、
- 詳細はいったん置いといて部分問題に分割して全体の流れを考える。
- 部分問題を解決する。
- それぞれによりよい方法がないか吟味する。
といったプロセスで考えることが多いです。
この問題の場合一次元的で図にするほどでもないですが、グラフやグリッド(二次元座標)、場合分けや状態遷移があるとき、問題文が複雑…などは図を書くのは大変有効です。
コーディング練習会の進め方でもstep1は分からなければ5分で見てもよいとありますし、知らないアルゴリズムは頑張ってもひらめかないので無理に自分に考え出さなくてもよいというスタンスで進めています。(実際mediumだと所見で解けないことのほうが多いです。)
制約は問題文の状況をspecifyする要素ですが、実際の面接試験などでは面接官とコミュニケーションをして把握するものらしいですし、実際の業務でもどのような入力がありうるか?どれくらいの処理時間で終わらせないといけないか?どいういったインターフェースにするか?というのは所与の要素というより適宜考えてデザインしていかないといけないものかと思います。
leetcodeで正解するためには制約の状況だけ考えれば十分ですが、コーディング練習会の趣旨としては、制約にない状況も含め幅を広げて考えるのがよいのかなと思います。(といいつつ私も想定外の入力に対してどう例外処理をするかとか、入力データに対してどれくらいの処理時間になるかの見積もりなどきちんとできていなのですが…)
There was a problem hiding this comment.
@maeken4
丁寧な回答を頂きありがとうございます。
他の方のプロセスを確認できて大変参考になりました。
問題の主旨と解答、他の方法を考えたりとしてますが、解法が出てこないですね。
解法を読んでも分からないことも沢山です。
コーディング練習会の進め方でもstep1は分からなければ5分で見てもよいとありますし、知らないアルゴリズムは頑張ってもひらめかないので無理に自分に考え出さなくてもよいというスタンスで進めています。(実際mediumだと所見で解けないことのほうが多いです。)
少しずつ、知識と選択肢と出来る事を増やしていくシンプルな事でしか解決しないですね。
焦らず一つひとつの問題と向き合ってみます。
| int numUniqueEmails(std::vector<std::string>& emails) { | ||
| std::set<std::string> result; | ||
| for (const auto& email : emails) { | ||
| std::string normalized_email; |
There was a problem hiding this comment.
コメントありがとうございます。確かに「データを正規化する」とった文脈とは意味合いが違いますね。
| private: | ||
| std::string normalized_email(const std::string& email) { | ||
| auto at_position = email.find('@'); | ||
| auto local = email.substr(0, at_position); | ||
| auto at_domain = email.substr(at_position); | ||
| if (auto plus_position = local.find('+'); plus_position != std::string::npos) { | ||
| local.resize(plus_position); | ||
| } | ||
| std::erase(local, '.'); | ||
| return local + at_domain; | ||
| } | ||
| }; |
There was a problem hiding this comment.
ここを関数に切り出すのは賛成です。
ただ最初に step2-2.cpp が最終解なのかなと想ったので、関数化したほうがいいかもしれません、的なコメントをしそうになりました。stepX.cpp を作るのであれば、step3.cpp もあるとレビューしやすいかなと思いました (それか全て md に書くか)
There was a problem hiding this comment.
コメントありがとうございます。IDEの補助がないとつらいときに補助的にファイルを作っていたのですがレビューワーから見るとわかりにくいですね。紛らわしくならないように気を付けます
This Problem
https://leetcode.com/problems/unique-email-addresses/description/