diff --git a/arai60/kth_largest_element_in_a_stream/phase1.py b/arai60/kth_largest_element_in_a_stream/phase1.py new file mode 100644 index 0000000..ed03382 --- /dev/null +++ b/arai60/kth_largest_element_in_a_stream/phase1.py @@ -0,0 +1,21 @@ +# 普通に苦戦した +# 思考録: Quick selectアルゴリズムを思いつく, だが動的に配列が変化するので無駄に計算が増え, 他に効率が良いものがないか考える +# じゃあdequeでmax_len=kを指定してやれば良いかなと思ったが, これだと結局途中に要素を挿入するときに時間計算量がO(k)程度かかるので断念 +# 要素数をkに保ったmin_heapのrootを出力する方向で制作, これなら挿入操作もO(logk)程度で良い +# heapqを覚えていなかったのでhttps://docs.python.org/ja/3/library/heapq.htmlを確認した。 +# heapq.heapreplaceかheapq.heappushpopのどちらを使うか迷う。前者はpopしてからpush, 後者はpushしてからpopでどちらも要素数は保存されるのでどちらでも良いかなと思ったが... +class KthLargest: + + def __init__(self, k: int, nums: List[int]): + self.min_heap = [] # min_heap has k elements and min_heap[0] means the k-th largest element in the stream + self.k = k + for num in nums: + self.add(num) + + def add(self, val: int) -> int: + if len(self.min_heap) < self.k: + heapq.heappush(self.min_heap, val) + elif val > self.min_heap[0]: + heapq.heappushpop(self.min_heap, val) + + return self.min_heap[0] diff --git a/arai60/kth_largest_element_in_a_stream/phase2.py b/arai60/kth_largest_element_in_a_stream/phase2.py new file mode 100644 index 0000000..05dc4f1 --- /dev/null +++ b/arai60/kth_largest_element_in_a_stream/phase2.py @@ -0,0 +1,45 @@ +""" +Reference: +ryoooooory: https://github.com/ryoooooory/LeetCode/pull/15/files +seal-azarashi: https://github.com/seal-azarashi/leetcode/pull/8#pullrequestreview-2153924472 +Yoshiki-Iwasa: https://github.com/Yoshiki-Iwasa/Arai60/pull/7 +kazukiii: https://github.com/kazukiii/leetcode/pull/9/files +hayashi-ay: https://github.com/hayashi-ay/leetcode/pull/54/files +cheeseNA: https://github.com/cheeseNA/leetcode/pull/12/files + +add method以外でmin_heap propertyをいじって欲しくないのでアンダーバーをつけてprivateであることを主張して書くべきだと感じた +ryooooooryさんのコメントにあった: 順次追加処理かつソート操作に強いPriorityQueueで実装とあったので少し頭の片隅にいれておく + +""" +class KthLargest: + + def __init__(self, k: int, nums: List[int]): + self._min_heap = [] # _min_heap has k elements and _min_heap[0] means the k-th largest element in the stream + self.k = k + for num in nums: + self.add(num) + + def add(self, val: int) -> int: + if len(self._min_heap) < self.k: + heapq.heappush(self._min_heap, val) + elif val > self._min_heap[0]: + heapq.heappushpop(self._min_heap, val) + + return self._min_heap[0] + +# 別のheapq実装もためす。https://docs.python.org/ja/3/library/heapq.htmlにはheappushpopを使った方が1回ずつpushとpopを呼び出すよりも効率が良いので, 上の方が良い? +class KthLargest: + + def __init__(self, k: int, nums: List[int]): + self._min_heap = [] # _min_heap has k elements and _min_heap[0] means the k-th largest element in the stream + self.k = k + for num in nums: + self.add(num) + + def add(self, val: int) -> int: + # Add new value and pop until len(self._min_heap) == self.k + heapq.heappush(self._min_heap, val) + while len(self._min_heap) > self.k: + heapq.heappop(self._min_heap) + + return self._min_heap[0] diff --git a/arai60/kth_largest_element_in_a_stream/phase3.py b/arai60/kth_largest_element_in_a_stream/phase3.py new file mode 100644 index 0000000..546732c --- /dev/null +++ b/arai60/kth_largest_element_in_a_stream/phase3.py @@ -0,0 +1,15 @@ +class KthLargest: + + def __init__(self, k: int, nums: List[int]): + self._min_heap = [] # _min_heap has k elements and _min_heap[0] means the k-th largest element in the stream. + self.k = k + for num in nums: + self.add(num) + + def add(self, val: int) -> int: + if len(self._min_heap) < self.k: + heappush(self._min_heap, val) + elif val >= self._min_heap[0]: + heappushpop(self._min_heap, val) + + return self._min_heap[0]