From b2f59bd0daa4e87ba9c5cad8e200ceeefadb5caf Mon Sep 17 00:00:00 2001 From: kazukiii Date: Thu, 13 Jun 2024 17:25:56 -0700 Subject: [PATCH 1/2] =?UTF-8?q?step1,=20step2,=20step3=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ara60/top-k-frequent-elements/README.md | 39 ++++++++++++++ ara60/top-k-frequent-elements/step1.cpp | 25 +++++++++ ara60/top-k-frequent-elements/step2_heap.cpp | 24 +++++++++ .../step2_quick_select.cpp | 51 +++++++++++++++++++ ara60/top-k-frequent-elements/step3.cpp | 24 +++++++++ 5 files changed, 163 insertions(+) create mode 100644 ara60/top-k-frequent-elements/README.md create mode 100644 ara60/top-k-frequent-elements/step1.cpp create mode 100644 ara60/top-k-frequent-elements/step2_heap.cpp create mode 100644 ara60/top-k-frequent-elements/step2_quick_select.cpp create mode 100644 ara60/top-k-frequent-elements/step3.cpp diff --git a/ara60/top-k-frequent-elements/README.md b/ara60/top-k-frequent-elements/README.md new file mode 100644 index 0000000..ad1a377 --- /dev/null +++ b/ara60/top-k-frequent-elements/README.md @@ -0,0 +1,39 @@ +## 考察 +- 過去に解いたことあり +- 方針 + - まずはカウントを行う + - 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 + 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; + } +}; From f5a54b08b0d3a41910b1a9fdaf4761d28665b0ae Mon Sep 17 00:00:00 2001 From: kazukiii Date: Fri, 14 Jun 2024 17:56:11 -0700 Subject: [PATCH 2/2] =?UTF-8?q?step4=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ara60/top-k-frequent-elements/README.md | 9 +++++++ ara60/top-k-frequent-elements/step4.cpp | 34 +++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 ara60/top-k-frequent-elements/step4.cpp diff --git a/ara60/top-k-frequent-elements/README.md b/ara60/top-k-frequent-elements/README.md index ad1a377..f041e5c 100644 --- a/ara60/top-k-frequent-elements/README.md +++ b/ara60/top-k-frequent-elements/README.md @@ -37,3 +37,12 @@ - 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/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; + } + }; +};