Skip to content

703. Kth Largest Element in a Stream #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 30, 2025
Merged

703. Kth Largest Element in a Stream #8

merged 4 commits into from
May 30, 2025

Conversation

garunitule
Copy link
Owner

Copy link

@huyfififi huyfififi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

良いと思います!これはよもやま話ですが、heapqはmin-heapですが、入れる値の正負を逆転させてmax-heapにすることもできることを、私自身どこかで聞かれたような記憶があります。

heap_nums: List[int]

def __init__(self, k: int, nums: List[int]):
self.heap_nums = heapq.nlargest(k, nums)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nums

the stream of test scores

とあり、streamなので、stream processingとかを思い出すと、for文でひとつずつ処理していくことが想定解ではないでしょうか?

問題文が悪いですし、軽く調べてもよく分からず私も自信がないのですが... 😥

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

後のコメントでも触れていただいているのですが、nlargest+sortの方法だと読み手に考えさせてしまうのでより素直にfor文でnumsを回しながらaddする方法を選択しました!
4c0fb63


def __init__(self, k: int, nums: List[int]):
self.heap_nums = heapq.nlargest(k, nums)
self.heap_nums.sort()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorted listって、array実装のmin-heapなんですね 👀 heapがarrayでどう実装されているのか分からない読者にはheapify()の方が、heapである、という抽象度で止まって深掘りする必要がなくなるので親切かもしれません。これくらいは一般常識なのかもしれませんが 🤔

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

私は一瞬これheapになっているのか?と考えて問題ないことを確認しました。huyfififiさんと同じ意見です。

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

たしかにその通りですね。
nlargest + sortの方法だとヒープの実装までイメージする必要があって読み手に負荷をかけてしまいます
素直にfor文でnumsの要素を走査しながらaddする実装にしました

4c0fb63

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

シンプルで理解しやすくて良いと思います 👍


def __init__(self, k: int, nums: List[int]):
self.k = k
self.top_k_min_heap = sorted(heapq.nlargest(k, nums))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

私もtop_k_min_heap派ですが、クラス名とkというinstance attributeに既に情報があるので、単にmin_heapにしてしまう方もいるだろうな、と予想します。

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

「こういう人もいるだろう」コメント勉強になります
クラス名やkというコンテキストがあるので min_heap でも充分通じそうですね
これは好みになるんですが、min_heapだけ見たときに一瞬考えるかもなと思い top_k_min_heap が良いかなと思いました


def __init__(self, k: int, nums: List[int]):
self.k = k
self.top_k_min_heap = sorted(heapq.nlargest(k, nums))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self.top_k_min_heap = heapq.nlargest(k, nums)[::-1] でも可でしょうか。

- top_k_min_heap
とかかな?
データ構造を示さなくてよいなら、top_k_valsとかもありそう。
今回はヒープであることを明示したいので、top_k_min_heapがよさそう。

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PythonではheapはただのListを介して操作されるのでわかりにくい印象で、変数名に書く方法はわかりやすいと思いました。

Copy link
Owner Author

@garunitule garunitule left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@huyfififi @tokuhirat
レビューありがとうございます!
コメント返信しました

heap_nums: List[int]

def __init__(self, k: int, nums: List[int]):
self.heap_nums = heapq.nlargest(k, nums)
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

後のコメントでも触れていただいているのですが、nlargest+sortの方法だと読み手に考えさせてしまうのでより素直にfor文でnumsを回しながらaddする方法を選択しました!
4c0fb63


def __init__(self, k: int, nums: List[int]):
self.heap_nums = heapq.nlargest(k, nums)
self.heap_nums.sort()
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

たしかにその通りですね。
nlargest + sortの方法だとヒープの実装までイメージする必要があって読み手に負荷をかけてしまいます
素直にfor文でnumsの要素を走査しながらaddする実装にしました

4c0fb63


def __init__(self, k: int, nums: List[int]):
self.k = k
self.top_k_min_heap = sorted(heapq.nlargest(k, nums))
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

「こういう人もいるだろう」コメント勉強になります
クラス名やkというコンテキストがあるので min_heap でも充分通じそうですね
これは好みになるんですが、min_heapだけ見たときに一瞬考えるかもなと思い top_k_min_heap が良いかなと思いました


```python
import heapq
class KthLargest:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit

PEP8 - Blank Lines

Surround top-level function and class definitions with two blank lines.

とあり、import文とその他ロジックは2つのblank linesで分けていただいた方が無難かと思います。

Comment on lines +39 to +40
self.heap_nums = heapq.nlargest(k, nums)
self.heap_nums.sort()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nlargest + sort でもいいんですが、nlargest の中身を読むと、全部 heap にいれて k 個取り出すとかだったと思います。そう考えると何か二度手間をしている感じがします。小さい方から k 個取り出すだけならば、アルゴリズムとしては、quickselect があるんですが (C++ だと nth_element) Python だとなさそうですね。

なんとなく被っているのと、sort で heap を作っているのが驚きを与えそうですね。sort よりも heapq.heapify を使ったほうが素直でしょう。

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nlargestの実装

  • n要素取ってきてheapify
  • 残りの要素をheapreplace
  • ソート
    という処理になっていました

なのでnlargest + sortは2回ソートしているので2度手間になっていますね

quickselectを確認し、実装してみました
c53131e

https://github.com/shintaro1993/arai60/pull/12/files
2分探索で解く方法もある。
addにO(logn)(nはnumsの要素数)かかる。k<=n+1なのでヒープを使った解法のほうが早そう。
と思ったけど、最初にソートしてk番目までの最大値をソートされたまま保持しておけばO(logk)でaddできるか
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

こういうソートされた状態での追加削除は、平衡二分木の出番なんですが、Python だと標準にはなくて、標準ではないけれども SortedContainers などを使うことが多いです。
https://grantjenks.com/docs/sortedcontainers/

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

なるほど、実装してみました。
1117820

@garunitule garunitule merged commit be30625 into main May 30, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants