diff --git a/problems/703.kth-largest-element-in-a-stream/memo.md b/problems/703.kth-largest-element-in-a-stream/memo.md new file mode 100644 index 0000000..2de1a95 --- /dev/null +++ b/problems/703.kth-largest-element-in-a-stream/memo.md @@ -0,0 +1,57 @@ +## step1 +- 二分探索木みたいなのに追加していって調べるのがいいのか? + - 普通のリストだと追加が遅いと思った +- 計算量がだいぶうろ覚え +- とりあえず最良ではないけど毎回並び替えて解くようにする +- sortが出てくるたびsortとsortedどっちがどっちだったかと降順・昇順どっちがデフォルトだったか毎回調べてる +- sort済みなのでbisect.insort()で追加していくO(logN)だったと思う + - 調べたら場所を調べるのはO(logN)だが追加はO(N)でやっぱり遅い + - 同じ数値だった場合左から追加か右から追加かは今回気にしない + - insortはinsort_rightと一緒みたい + - importのやり方も好まれるやり方がありそう +- https://note.nkmk.me/python-list-clear-pop-remove-del/ +- k番目を取り出す時にpopを使う時に末尾に近いほど計算量が少なくて済むので今回は小さい順に並んでた方が最悪計算量がマシになりそう + - 実際にはどのくらいの倍率かどうかを調べる必要がありそう + - VS Codeの拡張のtestが動かなくなった + - 抜き出さなくてよかった + - それなら毎回上位kだけ保持すればいい + - pop(0)はやっぱり遅い + - pop()にするためには値を全て負にして入れないといけなくなり手間がかかる。。。 +## step2 +- heapqを使うと良いみたい + - 追加時にO(logN) + - K番目に大きい/小さい値heapq.nlargest(k, iterable) / nsmallest(k, iterable): (O(NlogK)) (Kが大きい場合は効率的)  + - 一旦step2-1としてheapqの使い方を調べて解いてみる + - 多分やりたいことは合ってるはずだが、TLEした + - 計算量は最初heapq.heapifyでO(N)、addでO(NlogK) + - step1では最初のsortでO(NlogN),addでbisect.insortでO(N)でKが大きい時にstep1の方が早かった + - 今回の問題ではNと比較してKが小さいとかないので上位のみでカットする方法は最悪計算量は変わらなさそう + - 遅くなりことはおそらくないのでやれるならやった方が良い? + - 最小値の取得はheap[0] (最小値の取得): O(1)で行えるのでそこで早くなる(step2-2) + - これで劇的に早くなった26ms(メモリは25.71MB) + - step1も27msであまり変わらない(メモリは23.65MB) + - どっちが良いか考えたい + - 一旦他の人のコードを見る + - https://github.com/Hiroto-Iizuka/coding_practice/pull/8/files + - pushしてpopするための効率的な関数heapq.heappushpopがある + - https://github.com/mamo3gr/arai60/pull/8/files + - 全部入れてカットする方法はO(NlogN)で毎回カットする方ほうはO(NlogK)になる + - https://github.com/Yuto729/LeetCode_arai60/pull/14/files + - 計算時間が書いてあるのが良いと思った + - addにカットまで集約する + - 自前での実装はやっておくと、より親と子の位置関係などのイメージがつきそう + - https://github.com/kazizi55/coding-challenges/pull/8 + - `時間計算量から、どのくらいの処理時間がかかるか推定することをおすすめします。推定の方法は過去のコードレビューコメントにあると思いますので、探すことをおすすめします。` + - 処理時間の計算までしてなかったので、やるようにする + - `self.k -> self.capacity、self.top_k_nums -> self.largest_nums` + - 問題文のkを使うので問題はないと思うが、kという表記がない場合はcapacityはすごく良いと思った + +## step3 +- 詰まることなくかけた +- heapの計算量と操作をイメージしながら解いた + + + + +## TODO +[] 自作heapの実装 \ No newline at end of file diff --git a/problems/703.kth-largest-element-in-a-stream/step1-2.py b/problems/703.kth-largest-element-in-a-stream/step1-2.py new file mode 100644 index 0000000..c335bc4 --- /dev/null +++ b/problems/703.kth-largest-element-in-a-stream/step1-2.py @@ -0,0 +1,26 @@ +# +# @lc app=leetcode id=703 lang=python3 +# +# [703] Kth Largest Element in a Stream +# + + +# @lc code=start +from bisect import insort + + +class KthLargest: + def __init__(self, k: int, nums: List[int]): + self.k = k + self.sorted_nums = sorted(nums)[-k:] + + def add(self, val: int) -> int: + insort(self.sorted_nums, val) + if len(self.sorted_nums) > self.k: + self.sorted_nums.pop(0) + return self.sorted_nums[0] + + +# Your KthLargest object will be instantiated and called as such: +# obj = KthLargest(k, nums) +# param_1 = obj.add(val)# @lc code=end diff --git a/problems/703.kth-largest-element-in-a-stream/step1.py b/problems/703.kth-largest-element-in-a-stream/step1.py new file mode 100644 index 0000000..c252f5b --- /dev/null +++ b/problems/703.kth-largest-element-in-a-stream/step1.py @@ -0,0 +1,24 @@ +# +# @lc app=leetcode id=703 lang=python3 +# +# [703] Kth Largest Element in a Stream +# + + +# @lc code=start +from bisect import insort + + +class KthLargest: + def __init__(self, k: int, nums: List[int]): + self.k = k + self.sorted_nums = sorted(nums) + + def add(self, val: int) -> int: + insort(self.sorted_nums, val) + return self.sorted_nums[-self.k] + + +# Your KthLargest object will be instantiated and called as such: +# obj = KthLargest(k, nums) +# param_1 = obj.add(val)# @lc code=end diff --git a/problems/703.kth-largest-element-in-a-stream/step2-1.py b/problems/703.kth-largest-element-in-a-stream/step2-1.py new file mode 100644 index 0000000..f2ea660 --- /dev/null +++ b/problems/703.kth-largest-element-in-a-stream/step2-1.py @@ -0,0 +1,26 @@ +# +# @lc app=leetcode id=703 lang=python3 +# +# [703] Kth Largest Element in a Stream +# + +# @lc code=start +import heapq + + +class KthLargest: + def __init__(self, k: int, nums: List[int]): + self.k = k + self.heapifyed_values = nums + heapq.heapify(self.heapifyed_values) + + def add(self, val: int) -> int: + heapq.heappush(self.heapifyed_values, val) + + return heapq.nlargest(self.k, self.heapifyed_values)[-1] + + +# Your KthLargest object will be instantiated and called as such: +# obj = KthLargest(k, nums) +# param_1 = obj.add(val) +# @lc code=end diff --git a/problems/703.kth-largest-element-in-a-stream/step2-2.py b/problems/703.kth-largest-element-in-a-stream/step2-2.py new file mode 100644 index 0000000..b9a9d21 --- /dev/null +++ b/problems/703.kth-largest-element-in-a-stream/step2-2.py @@ -0,0 +1,32 @@ +# +# @lc app=leetcode id=703 lang=python3 +# +# [703] Kth Largest Element in a Stream +# + +# @lc code=start +import heapq + + +class KthLargest: + def __init__(self, k: int, nums: List[int]): + self.k = k + self.heapifyed_values = nums + heapq.heapify(self.heapifyed_values) + self._trim_to_top_k() + + def add(self, val: int) -> int: + heapq.heappush(self.heapifyed_values, val) + self._trim_to_top_k() + + return self.heapifyed_values[0] + + def _trim_to_top_k(self): + while len(self.heapifyed_values) > self.k: + heapq.heappop(self.heapifyed_values) + + +# Your KthLargest object will be instantiated and called as such: +# obj = KthLargest(k, nums) +# param_1 = obj.add(val) +# @lc code=end diff --git a/problems/703.kth-largest-element-in-a-stream/step2-3.py b/problems/703.kth-largest-element-in-a-stream/step2-3.py new file mode 100644 index 0000000..acb310d --- /dev/null +++ b/problems/703.kth-largest-element-in-a-stream/step2-3.py @@ -0,0 +1,32 @@ +# +# @lc app=leetcode id=703 lang=python3 +# +# [703] Kth Largest Element in a Stream +# + +# @lc code=start +import heapq + + +class KthLargest: + def __init__(self, k: int, nums: List[int]): + self.k = k + self.top_k_values = [] + for n in nums: + self.add(n) + + def add(self, val: int) -> int: + heapq.heappush(self.top_k_values, val) + self._trim_to_top_k() + + return self.top_k_values[0] + + def _trim_to_top_k(self): + while len(self.top_k_values) > self.k: + heapq.heappop(self.top_k_values) + + +# Your KthLargest object will be instantiated and called as such: +# obj = KthLargest(k, nums) +# param_1 = obj.add(val) +# @lc code=end diff --git a/problems/703.kth-largest-element-in-a-stream/step3.py b/problems/703.kth-largest-element-in-a-stream/step3.py new file mode 100644 index 0000000..4f422b7 --- /dev/null +++ b/problems/703.kth-largest-element-in-a-stream/step3.py @@ -0,0 +1,33 @@ +# +# @lc app=leetcode id=703 lang=python3 +# +# [703] Kth Largest Element in a Stream +# + +# @lc code=start +import heapq + + +class KthLargest: + def __init__(self, k: int, nums: List[int]): + self.k = k + self.top_k_values = [] + + for n in nums: + self.add(n) + + def add(self, val: int) -> int: + heapq.heappush(self.top_k_values, val) + self._trim_to_top_k() + + return self.top_k_values[0] + + def _trim_to_top_k(self): + while len(self.top_k_values) > self.k: + heapq.heappop(self.top_k_values) + + +# Your KthLargest object will be instantiated and called as such: +# obj = KthLargest(k, nums) +# param_1 = obj.add(val) +# @lc code=end