diff --git a/Top K Frequent Elements (retry)/memo.md b/Top K Frequent Elements (retry)/memo.md new file mode 100644 index 0000000..b68d3a3 --- /dev/null +++ b/Top K Frequent Elements (retry)/memo.md @@ -0,0 +1,47 @@ +# step1 + +メタ情報でpriority queueを使用しようと思いました。 +ただどうも良いやり方が思いつかず、解答にあったコードを参考にして写経してあります。 + +# step2 + +## 典型コメント集をみて + +- https://discord.com/channels/1084280443945353267/1235829049511903273/1245555256360697949 + - Counterを使うのはいいが、その実装を理解しているかが出題者の意図なのでは + - dictを初期化、その後listを作成しsortして上位何件かを取るという処理ができているか +- https://discord.com/channels/1084280443945353267/1183683738635346001/1185972070165782688 + - QuickSelectというアルゴリズムがある + - https://www.geeksforgeeks.org/dsa/quickselect-algorithm/ + + + +## Bucket Sort + +Bucket Sortという方法があった。 +2次元配列のインデックスを頻度として使用し、対象インデックスの配列に対して番号を追加していく方式。 + +時間計算量 O(N) + - numsの要素分のループが定数倍回行われるのみなので、O(N)なはず。 +空間計算量 O(N) +- bucket用のリストを確保するので、空間計算量はO(N) + +## Heap + +Min-heapを使う方法。 +Min heapに対して、(頻度,番号)のタプルを追加し、k個以上の要素が追加された場合 heappop する。つまり、heapの中には常に tok k frequent elements のみが存在する状態。 + +時間計算量 O(NlogK) + - heapを構成する要素数は必ずK個以下になるので、O(NlogK)なはず。 +空間計算量 O(N+K) +- N個の要素 + +## Sort + +シンプルにSortする方法 +[頻度,番号]のリストをリストに追加して、ソートする。(あとで突っ込む値はリストからタプルに変えた) + +時間計算量 O(NlogN) + - N個の要素を持つリストをソートするのでNlogNななず。 +空間計算量 O(N) +- N個の要素を持つリストを作成するため。 diff --git a/Top K Frequent Elements (retry)/step1.py b/Top K Frequent Elements (retry)/step1.py new file mode 100644 index 0000000..ae34fbf --- /dev/null +++ b/Top K Frequent Elements (retry)/step1.py @@ -0,0 +1,18 @@ +class Solution: + def topKFrequent(self, nums: List[int], k: int) -> List[int]: + count = {} + for num in nums: + count[num] = 1 + count.get(num, 0) + + heap = [] + for num in count.keys(): + heapq.heappush(heap, (count[num], num)) + if len(heap) > k: + heapq.heappop(heap) + + res = [] + for i in range(k): + res.append(heapq.heappop(heap)[1]) + + return res + diff --git a/Top K Frequent Elements (retry)/step2-using-bucket-sort.py b/Top K Frequent Elements (retry)/step2-using-bucket-sort.py new file mode 100644 index 0000000..9af66f4 --- /dev/null +++ b/Top K Frequent Elements (retry)/step2-using-bucket-sort.py @@ -0,0 +1,17 @@ +class Solution: + def topKFrequent(self, nums: List[int], k: int) -> List[int]: + num_to_frequency = {} + frequency_to_nums = [ [] for i in range(len(nums) + 1)] + + for num in nums: + num_to_frequency[num] = 1 + num_to_frequency.get(num, 0) + for num, frequency in num_to_frequency.items(): + frequency_to_nums[frequency].append(num) + + res = [] + for i in range(len(frequency_to_nums) - 1, 0, -1): + for num in frequency_to_nums[i]: + res.append(num) + if len(res) == k: + return res + diff --git a/Top K Frequent Elements (retry)/step2-using-heap.py b/Top K Frequent Elements (retry)/step2-using-heap.py new file mode 100644 index 0000000..996bedb --- /dev/null +++ b/Top K Frequent Elements (retry)/step2-using-heap.py @@ -0,0 +1,16 @@ +class Solution: + def topKFrequent(self, nums: List[int], k: int) -> List[int]: + count = {} + for num in nums: + count[num] = 1 + count.get(num, 0) + + heap = [] + for num in count.keys(): + heapq.heappush(heap, (count[num], num)) + if len(heap) > k: + heapq.heappop(heap) + + res = [] + for _ in range(k): + res.append(heapq.heappop(heap)[1]) + return res diff --git a/Top K Frequent Elements (retry)/step2-using-quickselect.py b/Top K Frequent Elements (retry)/step2-using-quickselect.py new file mode 100644 index 0000000..cbe7e75 --- /dev/null +++ b/Top K Frequent Elements (retry)/step2-using-quickselect.py @@ -0,0 +1,44 @@ +class Solution: + def topKFrequent(self, nums: List[int], k: int) -> List[int]: + counts = {} + for num in nums: + counts[num] = 1 + counts.get(num, 0) + items = list(counts.items()) + n = len(items) + + if k >= n: + return [num for num, _ in items] + + target = n - k + + def partition(left: int, right: int, pivot_index: int) -> int: + pivot_freq = items[pivot_index][1] + + items[pivot_index], items[right] = items[right], items[pivot_index] + store_index = left + + for i in range(left, right): + if items[i][1] < pivot_freq: + items[store_index], items[i] = items[i], items[store_index] + store_index += 1 + items[store_index], items[right] = items[right], items[store_index] + return store_index + + def quickselect(left: int, right: int, k_smallest: int) -> None: + if left == right: + return + pivot_index = random.randint(left, right) + pivot_index = partition(left, right, pivot_index) + + if k_smallest == pivot_index: + return + elif k_smallest < pivot_index: + quickselect(left, pivot_index - 1, k_smallest) + else: + quickselect(pivot_index + 1, right, k_smallest) + + quickselect(0, n - 1, target) + top_k_nums = [num for num, _ in items[target:]] + return top_k_nums + + diff --git a/Top K Frequent Elements (retry)/step2-using-sort.py b/Top K Frequent Elements (retry)/step2-using-sort.py new file mode 100644 index 0000000..ab7b84c --- /dev/null +++ b/Top K Frequent Elements (retry)/step2-using-sort.py @@ -0,0 +1,17 @@ +class Solution: + def topKFrequent(self, nums: List[int], k: int) -> List[int]: + num_to_frequency = {} + for num in nums: + num_to_frequency[num] = 1 + num_to_frequency.get(num, 1) + + frequency_to_num_array = [] + for num, frequency in num_to_frequency.items(): + frequency_to_num_array.append([frequency, num]) + frequency_to_num_array.sort() + + res = [] + while len(res) < k: + res.append(frequency_to_num_array.pop()[1]) + return res + + diff --git a/Top K Frequent Elements (retry)/step3-using-bucket-sort.py b/Top K Frequent Elements (retry)/step3-using-bucket-sort.py new file mode 100644 index 0000000..fd72b19 --- /dev/null +++ b/Top K Frequent Elements (retry)/step3-using-bucket-sort.py @@ -0,0 +1,15 @@ +class Solution: + def topKFrequent(self, nums: List[int], k: int) -> List[int]: + counts = {} + frequency_buckets = [[] for _ in range(len(nums) + 1)] + + for num in nums: + counts[num] = 1 + counts.get(num, 0) + for num, cnt in counts.items(): + frequency_buckets[cnt].append(num) + result = [] + for frequency_value in range(len(frequency_buckets) - 1, 0, -1): + for num in frequency_buckets[frequency_value]: + result.append(num) + if len(result) == k: + return result diff --git a/Top K Frequent Elements (retry)/step3-using-heap.py b/Top K Frequent Elements (retry)/step3-using-heap.py new file mode 100644 index 0000000..d3bb00e --- /dev/null +++ b/Top K Frequent Elements (retry)/step3-using-heap.py @@ -0,0 +1,14 @@ +class Solution: + def topKFrequent(self, nums: List[int], k: int) -> List[int]: + counts = {} + for num in nums: + counts[num] = 1 + counts.get(num, 0) + heap = [] + for num, freq in counts.items(): + heapq.heappush(heap, (freq, num)) + if len(heap) > k: + heapq.heappop(heap) + result = [] + while heap: + result.append(heapq.heappop(heap)[1]) + return result diff --git a/Top K Frequent Elements (retry)/step3-using-sort.py b/Top K Frequent Elements (retry)/step3-using-sort.py new file mode 100644 index 0000000..4f59f0b --- /dev/null +++ b/Top K Frequent Elements (retry)/step3-using-sort.py @@ -0,0 +1,9 @@ +class Solution: + def topKFrequent(self, nums: List[int], k: int) -> List[int]: + counts = {} + for num in nums: + counts[num] = 1 + counts.get(num, 0) + freq_num_pairs = [(cnt, num) for num, cnt in counts.items()] + freq_num_pairs.sort(reverse=True) + result = [num for _, num in freq_num_pairs[:k]] + return result diff --git a/Top K Frequent Elements (retry)/step4-using-sort.py b/Top K Frequent Elements (retry)/step4-using-sort.py new file mode 100644 index 0000000..c7ce920 --- /dev/null +++ b/Top K Frequent Elements (retry)/step4-using-sort.py @@ -0,0 +1,10 @@ +class Solution: + def topKFrequent(self, nums: List[int], k: int) -> List[int]: + counts = {} + for num in nums: + counts[num] = 1 + counts.get(num, 0) + frequency_num_pairs = [] + for key, cnt in counts.items(): + frequency_num_pairs.append((cnt, key)) + frequency_num_pairs.sort(reverse=True) + return [num for _, num in frequency_num_pairs[:k]]