703. Kth Largest Element in a Stream - #8
Conversation
| - Timsort とはマージソートと挿入ソートを組み合わせたハイブリッドで安定なソートアルゴリズム | ||
| - https://en.wikipedia.org/wiki/Timsort | ||
|
|
||
| > `add()` を呼び出すたびに毎回ソートし、 `nums` のリストを生成しているため、 $10^4$ 回呼び出すと実行時間 2000ms 超となっていると想像 |
There was a problem hiding this comment.
時間計算量から、どのくらいの処理時間がかかるか推定することをおすすめします。推定の方法は過去のコードレビューコメントにあると思いますので、探すことをおすすめします。
There was a problem hiding this comment.
ありがとうございます。
確かに時間がどれくらいかかるかまで推定できた方が、実際プログラムが動く時のことやどこまでスケールさせられるかなども考えられて便利ですね!
クロック数を1GHzと仮定した場合に、最大実行時間としてはこの解法だと約14秒と推定することができました。
- 時間計算量が
$O(m × n \log n)$ なので、問題の制約に基づき、m = n = 10^4とした場合に、
$$10^8 × \log_2 10^4$$ になり、1.4 * 10^9 オペレーションになる。 - 1GHzの場合、1オペレーションはおよそ10nsかかる (10クロックサイクル)
- https://gist.github.com/jboner/2841832 を参考に、ざっくりL2キャッシュまでが効くと仮定
- 1秒間 (10^9 ns)だと、10^9 ns / 10ns = 10^8オペレーション行うことができる
- 1.4 * 10^9 / 10^8 = 14秒かかる
参考:
| self.k = k | ||
| self.top_k_nums = [] |
There was a problem hiding this comment.
自分なら、self.k -> self.capacity、self.top_k_nums -> self.largest_numsと命名すると思います。
There was a problem hiding this comment.
ありがとうございます。
問題文に寄せる形にしてみていた (k を意識的に使うようにした)のですが、問題文に関係なく、ご提示いただいた変数名の方が中身を自然に想像することができる気がして良いですね!
その変数名で step 4 として解き直してみました。
https://github.com/kazizi55/coding-challenges/pull/8/files#diff-164241027a674ce8299ec45934ed8147699b5494cc9e9a2027eeb8d142b1251eR19-R36
| @@ -0,0 +1,17 @@ | |||
| from heapq import heappush, heappop | |||
There was a problem hiding this comment.
自分が以前いただいたコメントより:
どのスタイルに準拠するかによりますが、たとえば Google では import itertools -> itertools.islice といった使い方をします。
https://google.github.io/styleguide/pyguide.html#22-imports
LeetCode で簡便のためこのようにインポートすることは問題ないと思いますが、スタイルによってバリエーションがあることは頭にあると良いかと思います。
https://discord.com/channels/1084280443945353267/1421920158506549470/1432896430477017110
There was a problem hiding this comment.
ありがとうございます!
知らなかったので勉強になりました。
一方で pep8 ではそのような決まりは特になかったので、やはりスタイルによってバリエーションがあるのですね。
https://peps.python.org/pep-0008/#imports
package や module 単位で import するように step 4で書き直してみました!
https://github.com/kazizi55/coding-challenges/pull/8/files#diff-164241027a674ce8299ec45934ed8147699b5494cc9e9a2027eeb8d142b1251eR19-R36
| if len(self.top_k_nums) > self.k: | ||
| self.top_k_nums.pop() |
There was a problem hiding this comment.
そもそもネストはそこまで深くないので好みですが、条件を反転してネストを浅くできるところは浅くするかなと思いました。
| if len(self.top_k_nums) > self.k: | |
| self.top_k_nums.pop() | |
| if len(self.top_k_nums) <= self.k: | |
| continue | |
| self.top_k_nums.pop() |
There was a problem hiding this comment.
ありがとうございます!
確かにネストを浅くできるところは極力浅くしておいた方が読み手側の負荷が下がりそうでいいですね。
https://github.com/kazizi55/coding-challenges/pull/8/files#diff-164241027a674ce8299ec45934ed8147699b5494cc9e9a2027eeb8d142b1251eR9-R11
| class KthLargest: | ||
|
|
||
| def __init__(self, k: int, nums: List[int]): | ||
| self.list = sorted(nums, reverse=True) |
There was a problem hiding this comment.
listであることは明白ですので自分ならsorted_numsなどの変数名にしたいと思いました。
https://leetcode.com/problems/kth-largest-element-in-a-stream/description/
Next: https://leetcode.com/problems/top-k-frequent-elements/