-
Notifications
You must be signed in to change notification settings - Fork 0
703 kth largest element in a stream #9
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
MA-yo-TA
wants to merge
3
commits into
main
Choose a base branch
from
703-Kth-Largest-Element-in-a-Stream
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
Show all changes
3 commits
Select commit
Hold shift + click to select a range
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
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,33 @@ | ||
| # 703. Kth Largest Element in a Stream | ||
|
|
||
| <https://leetcode.com/problems/kth-largest-element-in-a-stream/> | ||
|
|
||
| ## step1(まず通す) | ||
|
|
||
| ヒープを書くのに自信がなかったので、最初にソートしてあとは2分探索で挿入してくコードを書いた。 | ||
| ヒープは書こうとしてとしてめちゃくちゃ時間をかけてしまった。非常に混乱しながら書いているのでとても効率の悪いコードになっている。時間がもったいないのでもっと早く他の人のコードを読みにいくべきだった。 | ||
|
|
||
| ## step2(整形&他の人のコードを読む) | ||
|
|
||
| - そもそも insert している時点で挿入部分の時間計算量が配列の長さnに対して O(n) あるので2分探索じゃなくていっそ線形に探索した方が楽だった | ||
| - heapq というライブラリがあるのでそれを使えば話が早そうではある | ||
| - <https://docs.python.org/ja/3.13/library/heapq.html> | ||
| - みなさん、max ヒープを作って k 回 pop するんじゃなくて、k 要素の min ヒープを作っていらっしゃる | ||
| - <https://github.com/shining-ai/leetcode/pull/8> など | ||
| - 「k番目に大きい=大きい方からk要素だけの中で最小」なので、こうすると判定が早い | ||
| - 簡単にセルフ実装してみた。最初 push を↓のように書いていて時間計算量がO(配列長さ) だなあと思っていたところ CPython では 末尾を pop してから先頭をその値で上書きしていた。なるほどいいやり方だ。 | ||
| - <https://github.com/python/cpython/blob/3.13/Lib/heapq.py#L137> | ||
| - 親の位置をビット演算で計算しているのも勉強になる | ||
| - <https://github.com/python/cpython/blob/06dce35b5a63ea653d6101d36a8afc0e922255c6/Lib/heapq.py#L212> | ||
| - 最初書いた時はクラスのメンバ変数として Minheap.heap を持たせたために self.heap を直接いじるメソッドと引数として受け取るメソッドが混在していたので改善した | ||
| - CPython の heapq は関数を集めた名前空間 | ||
|
|
||
| ```python | ||
| def pop(self) -> int: | ||
| head = self.heap[0] | ||
| # 配列をスライスしているので O(k) かかるがそれで良いのかと思ったが | ||
| self.heap = self.heapify(self.heap[1:]) | ||
| return head | ||
| ``` | ||
|
|
||
| ## step3(10分以内にさっとかける * 3回) |
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,24 @@ | ||
| from typing import List | ||
|
|
||
|
|
||
| class KthLargest: | ||
| def __init__(self, k: int, nums: List[int]): | ||
| self.k = k | ||
| self.descending_nums = sorted(nums, reverse=True) | ||
|
|
||
| def add(self, val: int) -> int: | ||
| expanded_nums = [float("inf")] + self.descending_nums + [float("-inf")] | ||
| interval_head = 0 | ||
| interval_tail = len(expanded_nums) - 1 | ||
| interval_center = (interval_tail + interval_head) // 2 | ||
| while interval_head != interval_tail: | ||
| if val >= expanded_nums[interval_center]: | ||
| interval_tail = interval_center | ||
| interval_center = (interval_tail + interval_head) // 2 | ||
| else: | ||
| interval_head = interval_center + 1 | ||
| interval_center = (interval_tail + interval_head) // 2 | ||
|
|
||
| self.descending_nums.insert(interval_head - 1, val) | ||
|
|
||
| return self.descending_nums[self.k - 1] |
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,41 @@ | ||
| from typing import List | ||
|
|
||
|
|
||
| class KthLargest: | ||
| def __init__(self, k: int, nums: List[int]): | ||
| self.k = k | ||
| self.max_heap_nums = self.max_heapify(nums) | ||
|
|
||
| def max_heapify_root(self, nums: List[int], parent: int, tail: int): | ||
| while True: | ||
| left_child = parent * 2 + 1 | ||
| right_child = (parent + 1) * 2 | ||
| largest = parent | ||
| if left_child <= tail and nums[largest] < nums[left_child]: | ||
| largest = left_child | ||
| if right_child <= tail and nums[largest] < nums[right_child]: | ||
| largest = right_child | ||
|
|
||
| if largest != parent: | ||
| nums[parent], nums[largest] = nums[largest], nums[parent] | ||
| parent = largest | ||
| else: | ||
| return | ||
|
|
||
| def max_heapify(self, nums: List[int]): | ||
|
|
||
| tail = len(nums) - 1 | ||
| for parent in range(len(nums) // 2, -1, -1): | ||
| self.max_heapify_root(nums, parent, tail) | ||
|
|
||
| return nums | ||
|
|
||
| def add(self, val: int) -> int: | ||
| self.max_heap_nums = [val] + self.max_heap_nums | ||
| self.max_heapify_root(self.max_heap_nums, 0, len(self.max_heap_nums) - 1) | ||
| rest = self.max_heap_nums | ||
| for _ in range(self.k): | ||
| rest_largest = rest[0] | ||
| rest = self.max_heapify(rest[1:]) | ||
|
|
||
| return rest_largest |
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,74 @@ | ||
| from typing import List | ||
|
|
||
|
|
||
| class KthLargest: | ||
| def __init__(self, k: int, nums: List[int]): | ||
| self.k = k | ||
| self.k_largest_elements = self.heapify(nums) | ||
|
|
||
| def add(self, val: int) -> int: | ||
| self.push(self.k_largest_elements, val) | ||
| return self.k_largest_elements[0] | ||
|
|
||
| def _parent(self, child: int) -> int: | ||
| return (child - 1) // 2 | ||
|
|
||
| def _left_child(self, parent: int) -> int: | ||
| return parent * 2 + 1 | ||
|
|
||
| def _right_child(self, parent: int) -> int: | ||
| return (parent + 1) * 2 | ||
|
|
||
| def _shift_up(self, heap: List[int], index: int): | ||
| while index > 0 and heap[index] < heap[self._parent(index)]: | ||
| heap[index], heap[self._parent(index)] = ( | ||
| heap[self._parent(index)], | ||
| heap[index], | ||
| ) | ||
| index = self._parent(index) | ||
|
|
||
| def _shift_down(self, heap: List[int], index: int): | ||
| heap_size = len(heap) | ||
| while True: | ||
| smallest = index | ||
| if ( | ||
| self._left_child(index) < heap_size | ||
| and heap[self._left_child(index)] < heap[smallest] | ||
| ): | ||
| smallest = self._left_child(index) | ||
| if ( | ||
| self._right_child(index) < heap_size | ||
| and heap[self._right_child(index)] < heap[smallest] | ||
| ): | ||
| smallest = self._right_child(index) | ||
|
|
||
| if smallest == index: | ||
| break | ||
| heap[index], heap[smallest] = ( | ||
| heap[smallest], | ||
| heap[index], | ||
| ) | ||
| index = smallest | ||
|
|
||
| def push(self, heap: List[int], num: int): | ||
| heap_size = len(heap) | ||
| if heap_size < self.k: | ||
| heap.append(num) | ||
| self._shift_up(heap, len(heap) - 1) | ||
| elif num > heap[0]: | ||
| heap[0] = num | ||
| self._shift_down(heap, 0) | ||
|
|
||
| def pop(self, heap: List[int]) -> int: | ||
| head = heap[0] | ||
| tail = heap.pop() | ||
| if heap: | ||
| heap[0] = tail | ||
| self._shift_down(heap, 0) | ||
| return head | ||
|
|
||
| def heapify(self, nums: List[int]) -> List[int]: | ||
| heap: List[int] = [] | ||
| for index in range(len(nums)): | ||
| self.push(heap, nums[index]) | ||
| return heap |
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,17 @@ | ||
| from typing import List | ||
| import heapq | ||
|
|
||
|
|
||
| class KthLargest: | ||
| def __init__(self, k: int, nums: List[int]): | ||
| self.k = k | ||
| self.k_largest_elements = [] | ||
| for num in nums: | ||
| self.add(num) | ||
|
|
||
| def add(self, val: int) -> int: | ||
| if len(self.k_largest_elements) < self.k: | ||
| heapq.heappush(self.k_largest_elements, val) | ||
| elif val > self.k_largest_elements[0]: | ||
| heapq.heappushpop(self.k_largest_elements, val) | ||
| return self.k_largest_elements[0] |
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.
ただの感想になってしまうんですが,最終形がとてもわかりやすかったです
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.
ありがとうございます!