diff --git a/347-Top-K-Frequent-Elements/note.md b/347-Top-K-Frequent-Elements/note.md new file mode 100644 index 0000000..6210e58 --- /dev/null +++ b/347-Top-K-Frequent-Elements/note.md @@ -0,0 +1,35 @@ +# 347. Top K Frequent Elements + + + +## step1(まず通す) + +値→回数でカウントした後に回数→値の変換が高速にできて回数の大小でトータルオーダーのものが欲しいと思って Frequency を定義したけど冷静に考えると [回数, 値]のリストで良かった(List の順序は辞書順で判定)。 + +nums の長さを n としたとき、時間計算量は + +- カウント部分が O(n) +- ヒープ化が O(n) +- 取り出すところが pop O(log n) をk 回で O(k log n) + +なので O(k * log n) + +空間計算量は長さ n か k の配列(中身は固定サイズ)をいくつか持っているのとあとは定数だけなので O(n) + +## step2(整形&他の人のコードを読む) + +ひとまずリストで書いてみた。 + +- + - 自分が欲しかったものとして bidict というやつがあるらしい + - + - 自分の手でアルゴリズムを書かないとしたら Counter が便利 + - 逆引き辞書を `{回数: [その回数出てきた値のリスト]}` で持っておけばバケットソートできて速そう + - クイックセレクトという、クイックソートの類似のアルゴリズムがあるらしい + - ヒープじゃなくてソートして先頭k個を取ってくるなら、`{値: 回数}` 辞書のまま value でソートするという方法があるらしい + - +- heapq.heapify_max() などの max 系は 3.14 から使えるようになった新しい機能 + - + - minheap しか使えないなら回数を符号反転で持つことで解決できる + +## step3(10分以内にさっとかける * 3回) diff --git a/347-Top-K-Frequent-Elements/step1.py b/347-Top-K-Frequent-Elements/step1.py new file mode 100644 index 0000000..2ab868a --- /dev/null +++ b/347-Top-K-Frequent-Elements/step1.py @@ -0,0 +1,41 @@ +from functools import total_ordering +from typing import Dict, List +import heapq + + +@total_ordering +class Frequency: + def __init__(self, value: int, count: int): + self.value = value + self.count = count + + def __eq__(self, other: object) -> bool: + if not isinstance(other, self.__class__): + return NotImplemented + return self.count == other.count + + def __lt__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + return self.count < other.count + + def count_up(self): + self.count += 1 + + +class Solution: + def topKFrequent(self, nums: List[int], k: int) -> List[int]: + frequency_counter: Dict[int, Frequency] = {} + for num in nums: + if frequency_counter.get(num) is None: + frequency_counter[num] = Frequency(num, 1) + else: + frequency_counter[num].count_up() + + frequency_counts = list(frequency_counter.values()) + heapq.heapify_max(frequency_counts) + k_most_frequent_elements = [] + while len(k_most_frequent_elements) < k: + k_most_frequent_elements.append(heapq.heappop_max(frequency_counts).value) + + return k_most_frequent_elements diff --git a/347-Top-K-Frequent-Elements/step2.py b/347-Top-K-Frequent-Elements/step2.py new file mode 100644 index 0000000..fe1781a --- /dev/null +++ b/347-Top-K-Frequent-Elements/step2.py @@ -0,0 +1,20 @@ +from typing import Dict, List +import heapq + + +class Solution: + def topKFrequent(self, nums: List[int], k: int) -> List[int]: + frequency_counter: Dict[int, List[int]] = {} + for num in nums: + if frequency_counter.get(num) is None: + frequency_counter[num] = [1, num] + else: + frequency_counter[num][0] += 1 + + frequency_counts = list(frequency_counter.values()) + heapq.heapify_max(frequency_counts) + k_most_frequent_elements = [] + while len(k_most_frequent_elements) < k: + k_most_frequent_elements.append(heapq.heappop_max(frequency_counts)[1]) + + return k_most_frequent_elements diff --git a/347-Top-K-Frequent-Elements/step3.py b/347-Top-K-Frequent-Elements/step3.py new file mode 100644 index 0000000..1f2d436 --- /dev/null +++ b/347-Top-K-Frequent-Elements/step3.py @@ -0,0 +1,20 @@ +from typing import Dict, List +import heapq + + +class Solution: + def topKFrequent(self, nums: List[int], k: int) -> List[int]: + # counter の value は [回数, 値]のリスト + counter: Dict[int, List[int]] = {} + for num in nums: + if counter.get(num) is None: + counter[num] = [1, num] + else: + counter[num][0] += 1 + + count_and_num = list(counter.values()) + heapq.heapify_max(count_and_num) + top_k = [] + while len(top_k) < k: + top_k.append(heapq.heappop_max(count_and_num)[1]) + return top_k