-
Notifications
You must be signed in to change notification settings - Fork 0
703. Kth Largest Element in a Stream #10
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
Open
TrsmYsk
wants to merge
1
commit into
main
Choose a base branch
from
TrsmYsk-patch-6
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
266 changes: 266 additions & 0 deletions
266
703 Kth Largest Element in a Stream/703 Kth Largest Element in a Stream.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,266 @@ | ||
| 703. Kth Largest Element in a Stream <https://leetcode.com/problems/kth-largest-element-in-a-stream/> | ||
|
|
||
| # step 1 | ||
| - Arai60のカテゴリー分けから、heapを使うと予想。 | ||
| - 自力で実装するのは時間がかかりそうなのでheapqモジュールを使う。```heap[0]```で最小要素にアクセスできるので、heapのサイズがkを超えないようにしておけばよさそう。\ | ||
| https://docs.python.org/3.13/library/heapq.html | ||
| - initでheapのサイズをkに抑える書き方をすぐに思いつかなかった。AIに相談してaddで追加する方法を教えてもらった。 | ||
| - 時間計算量: 初期リストサイズn, 定員k, 受験者数m | ||
| - init: O(nlogk) | ||
| - add: O((m-n)logk) | ||
| - 空間計算量: | ||
| - init: O(n) | ||
| - add: O(k) | ||
| ```python3 | ||
| import heapq | ||
|
|
||
| class KthLargest: | ||
|
|
||
| def __init__(self, k: int, nums: List[int]): | ||
| self.capacity = k | ||
| self.scores = [] | ||
| for score in nums: | ||
| self.add(score) | ||
|
|
||
| def add(self, val: int) -> int: | ||
| heapq.heappush(self.scores, val) | ||
| if len(self.scores) > self.capacity: | ||
| heapq.heappop(self.scores) | ||
| return self.scores[0] | ||
|
|
||
| ``` | ||
|
|
||
| # step 2 | ||
| - https://github.com/tokuhirat/LeetCode/pull/8/changes#r2072364808 | ||
| - 入力のnumsを破壊するか否か。step1の実装は壊さない方法だが、そこまで検討していなかった。今回の問題設定は入試の点数管理なので提出期限などが存在しているであろうことを考えると入力を壊さない方が安全か。 | ||
| - 破壊しないほうが原則的らしい。 https://github.com/rinost081/LeetCode/pull/9/changes#r1874734978 | ||
|
|
||
| - https://github.com/syoshida20/leetcode/pull/13/changes#r2051729666 | ||
| - heapの命名について。top_kの方がscoresよりも中身が伝わる気がする。 | ||
|
|
||
| - https://github.com/fuga-98/arai60/pull/9/changes#r1966485704 | ||
| - リストを使った方法。insortが最適化されているので、定数倍の違いが効くため速いらしい。この方法は選択肢に入っていなかった。 | ||
| - heapの方法も要素がkを超えたときはheappushpopを使うようにしてあり、参考になった。 | ||
|
|
||
| - https://github.com/katataku/leetcode/pull/8/changes#r1856437996 | ||
| - kが負の場合の処理も考えていなかった。入学試験の合格者の管理が目的なら間違ったまま動き続けるよりは止まってくれた方がよさそう。 | ||
|
|
||
| - https://github.com/Ryotaro25/leetcode_first60/pull/9/changes#r1619710596 | ||
| - C++だといきなりpriority queを検討するのは違和感があるらしい。pythonでもsorted listをまず検討すべきなのだろうか。 | ||
|
|
||
| - https://discord.com/channels/1084280443945353267/1192736784354918470/1194613857046503444 | ||
| - 小田さんのheapの実装。 | ||
|
|
||
| - https://github.com/python/cpython/blob/main/Lib/heapq.py | ||
| - cpythonのheapqの実装。 | ||
|
|
||
| ## 2-1: heapq | ||
| ```python3 | ||
| import heapq | ||
| from typing import List | ||
|
|
||
| class KthLargest: | ||
|
|
||
| def __init__(self, k: int, nums: List[int]): | ||
| if not isinstance(k, int) or k < 1: | ||
| raise ValueError("k must be positive integer") | ||
|
|
||
| self.k = k | ||
| self.top_k = [] | ||
| for score in nums: | ||
| self.add(score) | ||
|
|
||
| def add(self, val: int) -> int: | ||
| if len(self.top_k) < self.k: | ||
| heapq.heappush(self.top_k, val) | ||
| return self.top_k[0] | ||
| heapq.heappushpop(self.top_k, val) | ||
| return self.top_k[0] | ||
|
|
||
|
|
||
| ``` | ||
|
|
||
| ## 2-2: insort | ||
| ```python3 | ||
| import bisect | ||
| from typing import List | ||
|
|
||
| class KthLargest: | ||
|
|
||
| def __init__(self, k: int, nums: List[int]): | ||
| if not isinstance(k, int) or k < 1: | ||
| raise ValueError("k must be positive integer") | ||
| self.k = k | ||
| self.top_k = sorted(nums)[-k:] | ||
|
|
||
| def add(self, val: int) -> int: | ||
| bisect.insort(self.top_k, val) | ||
| if len(self.top_k) > self.k: | ||
| del self.top_k[0] | ||
| return self.top_k[0] | ||
|
|
||
| ``` | ||
|
|
||
|
|
||
| # step 3 | ||
| ## 3-1: heapq | ||
| ```python3 | ||
| import heapq | ||
| from typing import List | ||
|
|
||
| class KthLargest: | ||
|
|
||
| def __init__(self, k: int, nums: List[int]): | ||
| if not isinstance(k, int) or k < 1: | ||
| raise ValueError("k must be a positive integer") | ||
| self.k = k | ||
| self.top_k = [] | ||
| for score in nums: | ||
| self.add(score) | ||
|
|
||
| def add(self, val: int) -> int: | ||
| if len(self.top_k) < self.k: | ||
| heapq.heappush(self.top_k, val) | ||
| return self.top_k[0] | ||
|
|
||
| heapq.heappushpop(self.top_k, val) | ||
| return self.top_k[0] | ||
|
|
||
| ``` | ||
|
|
||
| ## 3-2: insort | ||
|
|
||
| ```python3 | ||
| import bisect | ||
| from typing import List | ||
|
|
||
| class KthLargest: | ||
|
|
||
| def __init__(self, k: int, nums: List[int]): | ||
| if not isinstance(k, int) or k < 1: | ||
| raise ValueError("k must be a positive integer") | ||
| self.k = k | ||
| self.top_k = sorted(nums) | ||
| if len(self.top_k) > k: | ||
| del self.top_k[:-k] | ||
|
|
||
| def add(self, val: int) -> int: | ||
| bisect.insort(self.top_k, val) | ||
| if len(self.top_k) > self.k: | ||
| del self.top_k[0] | ||
| return self.top_k[0] | ||
|
|
||
| ``` | ||
|
|
||
| # 自作 min heap | ||
|
|
||
| ```python3 | ||
| from typing import List | ||
|
|
||
| class MinHeap: | ||
|
|
||
| def __init__(self, data: List[int] = None): | ||
| self.v = [] | ||
| if data is not None: | ||
| self.heapify(data) | ||
|
|
||
| def __len__(self) -> int: | ||
| return len(self.v) | ||
|
|
||
| def is_empty(self) -> bool: | ||
| return len(self.v) == 0 | ||
|
|
||
| def get_min(self) -> int: | ||
| if self.is_empty(): | ||
| raise IndexError("get min from empty heap") | ||
| return self.v[0] | ||
|
|
||
| def _first_child(self, index: int) -> int: | ||
| return 2 * index + 1 | ||
|
|
||
| def _second_child(self, index: int) -> int: | ||
| return 2 * index + 2 | ||
|
|
||
| def _parent(self, index: int) -> int: | ||
| return (index - 1) // 2 | ||
|
|
||
| def _has_first_child(self, index: int) -> bool: | ||
| return self._first_child(index) < len(self.v) | ||
|
|
||
| def _has_second_child(self, index: int) -> bool: | ||
| return self._second_child(index) < len(self.v) | ||
|
|
||
| def _has_child(self, index: int) -> bool: | ||
| return self._has_first_child(index) | ||
|
|
||
| def _smaller_child(self, index: int) -> Optional[int]: | ||
| if not self._has_child(index): | ||
| return None | ||
|
|
||
| smaller_child = self._first_child(index) | ||
| if (self._has_second_child(index) and | ||
| self.v[self._second_child(index)] < self.v[smaller_child]): | ||
| smaller_child = self._second_child(index) | ||
| return smaller_child | ||
|
|
||
| def _swap(self, index1: int, index2: int) -> None: | ||
| self.v[index1], self.v[index2] = self.v[index2], self.v[index1] | ||
|
|
||
| def _shift_up(self, index: int) -> None: | ||
| while index > 0: | ||
| parent = self._parent(index) | ||
| if self.v[index] >= self.v[parent]: | ||
| break | ||
| self._swap(index, parent) | ||
| index = parent | ||
|
|
||
| def _shift_down(self, index: int) -> None: | ||
| while self._has_child(index): | ||
| smaller_child = self._smaller_child(index) | ||
| if self.v[index] <= self.v[smaller_child]: | ||
| break | ||
| self._swap(index, smaller_child) | ||
| index = smaller_child | ||
|
|
||
| def heappush(self, value: int) -> None: | ||
| self.v.append(value) | ||
| added_index = len(self.v)-1 | ||
| self._shift_up(added_index) | ||
|
|
||
| def heappop(self) -> int: | ||
| if self.is_empty(): | ||
| raise IndexError("pop from empty heap") | ||
|
|
||
| min_value = self.v[0] | ||
| self.v[0] = self.v[len(self.v)-1] | ||
| self.v.pop() | ||
| if self.is_empty(): | ||
| return min_value | ||
|
|
||
| self._shift_down(0) | ||
| return min_value | ||
|
|
||
| def heapify(self, data: List[int]) -> None: | ||
| self.v = data[:] | ||
| last_parent = len(self.v) // 2 - 1 | ||
| for index in range(last_parent, -1, -1): | ||
| self._shift_down(index) | ||
|
|
||
| class KthLargest: | ||
|
|
||
| def __init__(self, k: int, nums: List[int]): | ||
| if not isinstance(k, int) or k < 1: | ||
| raise ValueError("k must be a positive integer") | ||
|
|
||
| self.k = k | ||
| self.top_k = MinHeap(data=nums) | ||
| while len(self.top_k) > self.k: | ||
| self.top_k.heappop() | ||
|
|
||
| def add(self, val: int) -> int: | ||
| self.top_k.heappush(val) | ||
| if len(self.top_k) > self.k: | ||
| self.top_k.heappop() | ||
| return self.top_k.get_min() | ||
|
|
||
| ``` | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
これ、_has_parent 定義してもいいかもしれませんが、さすがにやりすぎですかね。