-
Notifications
You must be signed in to change notification settings - Fork 0
383. Ransom Note #15
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?
383. Ransom Note #15
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,54 @@ | ||
| # 383. Ransom Note | ||
|
|
||
| https://leetcode.com/problems/ransom-note/ | ||
|
|
||
| ## Comments | ||
|
|
||
| ### step1 | ||
|
|
||
| * 最初、「重複を許すset」みたいなデータ構造(検索や削除はO(1))があればいいのにな、と思った | ||
| * step2 で追記。`std::multiset`, `std::unordered_multiset` | ||
| * あったような気がするがぱっとわからなかったので map で実装してみた (unordered_map でもよかったが、平均計算量のよい map にしてみた。そこまで深い考察はない)。 | ||
| * しばらく間が空いたので範囲 for とか一瞬書き方を忘れていた。 | ||
| * 5:00 くらいで書いてみた | ||
|
|
||
| ### step2 | ||
|
|
||
| * int の map に `[]` でアクセスするとき、初期値は 0 になるので、`if (!char_count.contains(c) || char_count[c] == 0)` は単に `if (char_count[c] == 0)` でよかった気はする | ||
| * `[]` アクセスとか、`at` とかまだちょっと苦手 | ||
| * `[]` | ||
| * 範囲外アクセスをチェックしない。map だと新しい要素が作られる | ||
| * `at` | ||
| * 範囲外アクセスで例外を投げる。map ではキーが存在しなければ例外を投げる | ||
| * 基本的には `at` の方が安全、`[]` の方がチェックしない分ちょっとだけ高速 | ||
|
|
||
| * `std::multiset` | ||
| * https://cpprefjp.github.io/reference/set/multiset.html | ||
| * `std::unordered_multiset` | ||
| * https://cpprefjp.github.io/reference/unordered_set/unordered_multiset.html | ||
|
|
||
| * `multiset` 使ってみた。 | ||
| * `Solution1WA`: 最初、`erase` が 1 個だけ要素を削除すると思っていたが、キーに合致するものは全部削除するらしい | ||
| * `Solution1AC`: 正しくは iterator を使うみたい。`multiset` だときれいに (`Solution1WA` のように) 書ける想像をしていたが、これなら別に map でもいいかなという感じ | ||
| * ちみに `std::multiset.find` は O(logn)、`std::unordered_multiset.find` は avg. O(1), worst O(n) | ||
| * まあ内部実装 (binary tree vs. hash) を考えれば当然 | ||
| * https://cpprefjp.github.io/reference/set/multiset/find.html | ||
| * https://cpprefjp.github.io/reference/unordered_set/unordered_multiset/find.html | ||
| * `Solution2` | ||
| * > ransomNote and magazine consist of lowercase English letters. | ||
| * この制約見逃していた。これあるなら 26 文字なので、長さ 26 vector を用意して ++, -- していっても解ける | ||
| * vector 使ったが可変長配列である必要はないかもしれない。 | ||
| * 一応サイズと初期値を与えられるらしい。 | ||
| * `std::vector<int> char_count(26, 0);` みたいに、`variable_name(args)` という書き方でコンストラクタを呼ぶの、なんかちょっと慣れない。 | ||
| * Python なら `variable_name = ClassName(args)` とか | ||
| * C++ でも `std::vector<int> char_count = std::vector<int>(26, 0);` と書くことはできる。一旦オブジェクト作ってから変数に束縛するので無駄な処理がありそうだけど。 | ||
| * vector の初期化といえば initializer list とかもある。まあこれはまた違う話。 | ||
| * https://cpprefjp.github.io/lang/cpp11/initializer_lists.html | ||
| * `insert` vs. `emplace` | ||
| * `emplace` の「要素を直接つくる」とは何かと思ったが、そもそも `insert` はコンテナ外で一時オブジェクトを作ってそれをムーブしているらしい | ||
| * なので基本的には `emplace` (C++11)の方が効率が良く、そちらを使う | ||
|
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. Chromium と Google は、基本 insert を使えみたいですね。 「効率が良く」に対して、「それは何秒くらい速くなるのか、本当にディスアドバンテージはないのか」とまず感じます。「速度」はエンジニアリングをする上でかなり弱い根拠なんですね。 |
||
| * TODO: ムーブといえば、社内の詳しい人は move semantics について苦笑いしていた。あれが登場したときは色々あったらしい。そもそも move semantics の話よくわかっていないのでそのうちに調べる | ||
|
|
||
| ### step3 | ||
|
|
||
| * いくつかパターン書いたので今回は省略 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| class Solution { | ||
| public: | ||
| bool canConstruct(string ransomNote, string magazine) { | ||
| std::map<char> char_count; | ||
|
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. c++にあまり詳しくないのですが、こちらvalueの型は指定しなくてよいのでしょうか? |
||
| for (char c : magazine) { | ||
| ++char_count[c]; | ||
| } | ||
| for (char c : ransomNote) { | ||
| if (!char_count.contains(c) || char_count[c] == 0) { | ||
|
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. if (--char_count[c] < 0) {
return false;
}のほうがシンプルだと思います。 |
||
| return false; | ||
| } | ||
| --char_count[c]; | ||
| } | ||
| return true; | ||
| } | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| // WA - `erase` はそのキーの全ての要素を削除する | ||
|
|
||
| class Solution1WA { | ||
| public: | ||
| bool canConstruct(string ransomNote, string magazine) { | ||
| std::multiset<char> char_count; | ||
| for (char c : magazine) { | ||
| char_count.insert(c); | ||
| } | ||
| for (char c : ransomNote) { | ||
| if (!char_count.contains(c)) { | ||
| return false; | ||
| } | ||
| char_count.erase(c); | ||
| } | ||
| return true; | ||
| } | ||
| }; | ||
|
|
||
|
|
||
| class Solution1AC { | ||
| public: | ||
| bool canConstruct(string ransomNote, string magazine) { | ||
| std::multiset<char> char_count; | ||
| for (char c : magazine) { | ||
| char_count.insert(c); | ||
| } | ||
| for (char c : ransomNote) { | ||
| if (!char_count.contains(c)) { | ||
| return false; | ||
| } | ||
|
Comment on lines
+29
to
+31
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. この 3 行は消せると思います。 |
||
| auto it = char_count.find(c); | ||
| if (it == char_count.end()) { | ||
| return false; // no match found | ||
| } | ||
| char_count.erase(it); | ||
| } | ||
| return true; | ||
| } | ||
| }; | ||
|
|
||
| class Solution2 { | ||
| public: | ||
| bool canConstruct(string ransomNote, string magazine) { | ||
| std::vector<int> char_count(26, 0); | ||
| for (char c : magazine) { | ||
| ++char_count[c - 'a']; | ||
| } | ||
| for (char c : ransomNote) { | ||
| if (char_count[c - 'a'] == 0) { | ||
| return false; | ||
| } | ||
| --char_count[c - 'a']; | ||
| } | ||
| return true; | ||
|
|
||
| } | ||
| }; | ||
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.
平均計算量は unordered_map のほうが良いですが、一部の操作については map のほうが早い、だと思います。
https://chromium.googlesource.com/chromium/src/+/HEAD/base/containers/README.md#std_unordered_map-and-std_unordered_set