diff --git a/ara60/top-k-frequent-elements/README.md b/ara60/top-k-frequent-elements/README.md new file mode 100644 index 0000000..f041e5c --- /dev/null +++ b/ara60/top-k-frequent-elements/README.md @@ -0,0 +1,48 @@ +## 考察 +- 過去に解いたことあり +- 方針 + - まずはカウントを行う + - time: O(n), space: O(n) + - カウントした結果を元にtopkを算出 + - 方針は3つ程思い浮かぶ + - ソート + - nums.length <= 10^5 なので、計数ソートが良さそう + - time: O(n), space: O(n) + - クイックセレクト + - ランダムにpivotを決める + - pivotの左側にpivot以下のもの、右側にpivotより大きいものを集める + - pivotが何番目かが確定するので、どちら側にk番目があるかは明白 + - これを繰り返せばいい + - any orderなので、pivotがk番目に来たら、pivotとその左側を返せばいい + - time: O(n), space: O(1) + - ヒープを使う + - サイズkの最小ヒープを用意して、サイズを保つように入れていく + - time: O(n log k), space: O(k) +- 全部さくっと実装できるようにしておきたい +- まずはソートでやる +- あとは実装 + +## Step1 +- 計数ソートを実装した +- time: O(n), space: O(n) + +## Step2 +- ヒープとクイックセレクトでも実装してみた +- 3通り実装してみて、計数ソートとクイックセレクトは脳の負荷が高い +- ヒープ使ってやるのが一番良さそう +- あとC++、エラー内容がPythonよりわかりにくく感じた(これは慣れかもしれない) + +## Step3 +- 1回目: 3m02s +- 2回目: 2m45s +- 3回目: 2m30s + +## Step4 +- レビューを元に修正 +- 変数名の見直し + - num_count -> num_to_count + - min_heap -> min_count_and_nums + - key, value -> num, count +- 拡張for文のコロンの前後にはspaceを入れる +- pairの代わりにstructを使うように修正 + diff --git a/ara60/top-k-frequent-elements/step1.cpp b/ara60/top-k-frequent-elements/step1.cpp new file mode 100644 index 0000000..fc627ee --- /dev/null +++ b/ara60/top-k-frequent-elements/step1.cpp @@ -0,0 +1,25 @@ +class Solution { +public: + vector topKFrequent(vector& nums, int k) { + int n = nums.size(); + unordered_map num_count; + for (int num: nums) { + num_count[num]++; + } + + vector buckets(n + 1, 0); + for (auto [key, value]: num_count) { + buckets[value]++; + } + for (int i = 0; i < n; ++i) { + buckets[i + 1] += buckets[i]; + } + + vector sorted(num_count.size()); + for (auto [key, value]: num_count) { + sorted[--buckets[value]] = key; + } + + return vector(sorted.end() - k, sorted.end()); + } +}; diff --git a/ara60/top-k-frequent-elements/step2_heap.cpp b/ara60/top-k-frequent-elements/step2_heap.cpp new file mode 100644 index 0000000..00a54fb --- /dev/null +++ b/ara60/top-k-frequent-elements/step2_heap.cpp @@ -0,0 +1,24 @@ +class Solution { +public: + vector topKFrequent(vector& nums, int k) { + unordered_map count; + for (int num: nums) { + count[num]++; + } + + priority_queue, vector>, greater>> min_heap; + for (auto [key, value]: count) { + min_heap.push({value, key}); + if (min_heap.size() > k) { + min_heap.pop(); + } + } + + vector answer; + while (!min_heap.empty()) { + answer.push_back(min_heap.top().second); + min_heap.pop(); + } + return answer; + } +}; diff --git a/ara60/top-k-frequent-elements/step2_quick_select.cpp b/ara60/top-k-frequent-elements/step2_quick_select.cpp new file mode 100644 index 0000000..4fcecfe --- /dev/null +++ b/ara60/top-k-frequent-elements/step2_quick_select.cpp @@ -0,0 +1,51 @@ +class Solution { +public: + vector topKFrequent(vector& nums, int k) { + unordered_map count; + for (int num : nums) { + count[num]++; + } + + vector> frequency_to_num; + for (auto& [key, value] : count) { + frequency_to_num.push_back({value, key}); + } + + int n = frequency_to_num.size(); + quick_select(frequency_to_num, 0, n - 1, n - k); + vector answer; + for (int i = n - 1; i >= n - k; --i) { + answer.push_back(frequency_to_num[i].second); + } + return answer; + } + +private: + void quick_select(vector>& array, int left, int right, int k) { + while (left < right) { + int pivot_index = partition(array, left, right); + if (pivot_index == k) return; + else if (pivot_index < k) left = pivot_index + 1; + else right = pivot_index - 1; + } + } + + int partition(vector>& array, int left, int right) { + int pivot_index = rand_int(left, right); + int pivot_value = array[pivot_index].first; + swap(array[pivot_index], array[right]); + int store_index = left; + for (int i = left; i < right; ++i) { + if (array[i].first < pivot_value) { + swap(array[i], array[store_index]); + store_index++; + } + } + swap(array[store_index], array[right]); + return store_index; + } + + int rand_int(int from, int to) { + return from + rand() % (to - from + 1); + } +}; diff --git a/ara60/top-k-frequent-elements/step3.cpp b/ara60/top-k-frequent-elements/step3.cpp new file mode 100644 index 0000000..bd63272 --- /dev/null +++ b/ara60/top-k-frequent-elements/step3.cpp @@ -0,0 +1,24 @@ +class Solution { +public: + vector topKFrequent(vector& nums, int k) { + unordered_map num_count; + for (int num: nums) { + num_count[num]++; + } + + priority_queue, vector>, greater>> min_heap; + for (auto [key, value]: num_count) { + min_heap.push({value, key}); + if (min_heap.size() > k) { + min_heap.pop(); + } + } + + vector answer; + while (!min_heap.empty()) { + answer.push_back(min_heap.top().second); + min_heap.pop(); + } + return answer; + } +}; diff --git a/ara60/top-k-frequent-elements/step4.cpp b/ara60/top-k-frequent-elements/step4.cpp new file mode 100644 index 0000000..3999295 --- /dev/null +++ b/ara60/top-k-frequent-elements/step4.cpp @@ -0,0 +1,34 @@ +class Solution { +public: + vector topKFrequent(vector& nums, int k) { + unordered_map num_to_count; + for (int num : nums) { + num_to_count[num]++; + } + + priority_queue min_count_and_nums; + for (auto [num, count] : num_to_count) { + min_count_and_nums.push({count, num}); + if (min_count_and_nums.size() > k) { + min_count_and_nums.pop(); + } + } + + vector answer; + while (!min_count_and_nums.empty()) { + answer.push_back(min_count_and_nums.top().num); + min_count_and_nums.pop(); + } + return answer; + } + +private: + struct NumCount { + int count; + int num; + + bool operator<(const NumCount& other) const { + return count > other.count; + } + }; +};