-
Notifications
You must be signed in to change notification settings - Fork 0
Create 347. Top K Frequent Elements.md #22
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,103 @@ | ||
| # [347. Top K Frequent Elements](https://leetcode.com/problems/top-k-frequent-elements/description/) | ||
|
|
||
| ## Step1 | ||
| ### 問題意図の考察 | ||
| - 整数配列numsと整数kが与えられ、numsの中で最頻出するk個の要素を取り出す。 | ||
| - 頻度集計、効率的な上位k要素を取り出す。 | ||
| - 問題文より、O(nlogn)より良い計算量を目指す。 | ||
|
|
||
| ### 解法を考える | ||
| - バケットソート | ||
| * 数を数える -> num frequency (unordered_map<int, int>) | ||
| * 頻度ごとに箱へ格納 | ||
| * 高頻度側から取り出してk個集める | ||
|
|
||
| ```cpp | ||
| class Solution { | ||
| public: | ||
| std::vector<int> topKFrequent(const std::vector<int>& nums, int k) { | ||
| std::unordered_map<int, int> freq; | ||
|
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. 自分ならキーと値にそれぞれどのようなものが格納されているか分かりやすくするため、 num_to_frequency といった名前を付けると思います。
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. @nodchip 今回の問題ですが、frequenceyに関連するものが沢山出てきたため、ごちゃごちゃな命名となってしまいました。 |
||
| freq.reserve(nums.size()); | ||
| for (int x : nums) { | ||
| ++freq[x]; | ||
| } | ||
|
|
||
| std::vector<std::vector<int>> buckets(nums.size() + 1); | ||
| for (const auto& [val, f] : freq) { | ||
|
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. 関数の引数名が nums のため、 num としたほうが分かりやすいと思います。 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. f が何を表すのかやや分かりづらく感じました。 frequency とフルスペルで書くと分かりやすくなると思います。 1 文字変数は、 i や s 等インデックスを表したり文字列を表したりすることが想像しやすいもので、かつスコープが短いものであれば、十分わかりやすいと思います。今回はこれらに当てはまらないため、やや分かりづらく感じました。 |
||
| buckets[f].push_back(val); | ||
| } | ||
|
|
||
| std::vector<int> answer; | ||
| answer.reserve(k); | ||
| for (int f = static_cast<int>(buckets.size()) - 1; | ||
| f >= 1 && static_cast<int>(answer.size()) < k; --f) { | ||
| for (int val : buckets[f]) { | ||
| answer.push_back(val); | ||
| if (static_cast<int>(answer.size()) == k) break; | ||
| } | ||
| } | ||
| return answer; | ||
| } | ||
| }; | ||
|
|
||
| ``` | ||
|
|
||
| ## Step2 | ||
|
|
||
| ### コメント | ||
| - 解法がわからなかったので、参考のgithubより回答を確認。C++完走者をもう少し見つけたい。 | ||
|
|
||
| - https://discord.com/channels/1084280443945353267/1367399154200088626/1371325723612151918 | ||
| *実際の仕事を連想する | ||
|
|
||
| - std::nth_elements(線形時間) https://discord.com/channels/1084280443945353267/1183683738635346001/1185972070165782688 | ||
| * C. クイックセレクトについて | ||
| * 区間 [first, last) を完全には並べ替えず、イテレータ nth が指す要素を “ソート済みならそこに来る要素” にする。 | ||
| comp(x, *nth) == true な要素は nth より前へ | ||
| comp(*nth, x) == false な要素は nth 以降へ | ||
|
|
||
| - ハッシュ連想配列 ref: https://en.cppreference.com/w/cpp/container/unordered_map.html?utm_source=chatgpt.com | ||
| * テンプレート仮引数の見方が、少しずつわかってきた。ここでは、reserve()に関して確認。要素と出現回数 | ||
|
|
||
| - vector ref: https://en.cppreference.com/w/cpp/container/vector.html?utm_source=chatgpt.com | ||
| * 動的配列の性質(連続メモリ・再確保)、bucketsという命名は少し曖昧かな。ここでは、values_by_frequency とする。 | ||
| * freqもfrequencyへ変更。 | ||
|
|
||
| - アルゴリズム戦略 実装までの余裕はなかったが、考えられる選択肢を整理。 | ||
| * A. バケットソート -> 高頻度側からk個集める。 | ||
| * B. 最小ヒープ(priority_queue) -> (freq, val) を最小ヒープに入れ、サイズが k を超えたら pop。 | ||
| * C. クイックセレクト(選択アルゴリズム) -> (val, freq) の配列(サイズ u)を作り、第 k 大の頻度を基準に分割(平均 O(u)) | ||
| * D. 周波数でソート -> vector<pair<val,freq>> を freq 降順ソートして先頭 k 個。 | ||
|
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. 周波数ではなく頻度でしょうか。 |
||
|
|
||
|
|
||
| ```cpp | ||
| class Solution { | ||
| public: | ||
| std::vector<int> topKFrequent(const std::vector<int>& nums, int k) { | ||
| std::unordered_map<int, int> frequency; | ||
| frequency.reserve(nums.size()); | ||
| for (int x : nums) { | ||
| ++frequency[x]; | ||
| } | ||
|
|
||
| std::vector<std::vector<int>> values_by_frequency(nums.size() + 1); | ||
| for (const auto& [val, f] : frequency) { | ||
|
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. fが一文字変数でぱっと見何を意味するか分からないので
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. @nanae772 今回の問題ですが、frequenceyに関連するものが沢山出てきたため、ごちゃごちゃな命名となってしまいました。 |
||
| values_by_frequency[f].push_back(val); | ||
| } | ||
|
|
||
| std::vector<int> answer; | ||
|
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. answerは実際のところ何を表しているのかがあいまいなので別の名前などだと分かりやすいかなと思いました。 |
||
| answer.reserve(k); | ||
| for (int f = static_cast<int>(values_by_frequency.size()) - 1; | ||
| f >= 1 && static_cast<int>(answer.size()) < k; --f) { | ||
|
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. 94行目の
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. @nanae772 94行目 break; は 内側ループだけを抜け、外側ループはそのままだと 次の f に進みます。 確かにシンプルに書いた方がいいですね。もう一度書いてみます! 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. すみません、二重ループになっていたことを見落としていました 🙇♂️ |
||
| for (int val : values_by_frequency[f]) { | ||
| answer.push_back(val); | ||
| if (static_cast<int>(answer.size()) == k) break; | ||
| } | ||
| } | ||
| return answer; | ||
| } | ||
| }; | ||
|
|
||
| ``` | ||
|
|
||
| ## Step3 | ||
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.
私が勘違いしていたら申し訳ないですが,今回使われている手法はバケットソートとは別の方法ではないでしょうか.