-
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
# step1 | ||
- 愚直に解くなら、初期化時にforループ、その後addされるときにもforループを回す方法. | ||
|
||
- 計算効率を上げるなら、なんとなくキャッシュを作る方法とかがありそうな感じ. | ||
|
||
- forループを愚直に回すとしても、k番目以降は捨てて良いのでそれだけで効率化できそう. | ||
|
||
- リストに対するsortの仕方を忘れていた.sort()をする場合は、破壊的処理をするためにnum = num.sort()としたらNoneが出てくる. | ||
|
||
- この前の勉強会で講師の方がテストケースには空のものを想定するとおっしゃっていて実際のテストケースにも出てたから、それを常に意識するようにしたい. | ||
|
||
- 最終的にstep1で考えたのは、for文を使う方針(計算量を抑える方法が思いつかなかった)で、愚直に毎回for文で回すのではなく大きい順にK番目以降は刈り取ることで少し計算量を抑えた(K番目以降は見る必要がないので).しかしKが大きくなるにつれ刈り取る意味がなくなってくるアルゴリズムになっている. | ||
|
||
```python | ||
class KthLargest: | ||
|
||
def __init__(self, k: int, nums: List[int]): | ||
self.k = k | ||
self.sorted_nums = [] | ||
nums.sort(reverse=True) | ||
|
||
i = 0 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
if len(nums) != 0: | ||
while len(nums) > i and self.k != i: | ||
self.sorted_nums.append(nums[i]) | ||
i += 1 | ||
|
||
|
||
def add(self, val: int) -> int: | ||
if len(self.sorted_nums) < self.k: | ||
self.sorted_nums.append(val) | ||
self.sorted_nums.sort(reverse=True) | ||
elif self.sorted_nums[self.k-1] > val: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
https://peps.python.org/pep-0008/#other-recommendations
https://google.github.io/styleguide/pyguide.html#36-whitespace
|
||
pass | ||
elif self.sorted_nums[self.k-1] <= val: | ||
del self.sorted_nums[self.k-1] | ||
self.sorted_nums.append(val) | ||
self.sorted_nums.sort(reverse=True) | ||
|
||
return self.sorted_nums[self.k-1] | ||
``` | ||
|
||
# step2 | ||
参考にした方のPR | ||
- https://github.com/BumbuShoji/Leetcode/pull/9 | ||
- https://github.com/konnysh/arai60/pull/8#discussion\_r1866983937 | ||
- https://github.com/katataku/leetcode/pull/8#discussion\_r1862795689 | ||
- https://github.com/haniwachann/leetcode/pull/1 | ||
- https://github.com/tarinaihitori/leetcode/pull/8 | ||
|
||
- step1のadd()関数の中でソート済みのリストに追加した後,再度sortをしているがそうするよりも前から比較して入ってinsertする場所を探すというコメントがあった、その通りな気がする. | ||
- heapに気付けなかった→どうしたら気付けるのか | ||
- pythonにはSortedList()というものがある→nums.sort(), sorted(nums), nums = SortedList()の違いって何 | ||
|
||
## heapを使った解法 | ||
heapは最小(大)値をO(logN)で取り出し、要素をO(logN)で挿入する. またself.addをそのまま使っているため__init__では簡単な処理を書くだけで済む | ||
|
||
```python | ||
class KthLargest: | ||
|
||
def __init__(self, k: int, nums: List[int]): | ||
self.k = k | ||
self.k_largest_nums = [] | ||
|
||
for num in nums: | ||
self.add(num) | ||
|
||
def add(self, val: int) -> int: | ||
heapq.heappush(self.k_largest_nums, val) | ||
|
||
while self.k < len(self.k_largest_nums): | ||
heapq.heappop(self.k_largest_nums) | ||
return self.k_largest_nums[0] | ||
``` | ||
|
||
## nums.sort(), sorted(nums), nums = SortedList()の違いとheapとの比較 | ||
- sort()とsorted()の違いは、前者が元のリストを変えるのに対して後者は新しいリストを作成して元のリストには影響がない点. | ||
- SortedList()は追加したときに自動的にsortされる点 | ||
- sort()とsorted()はTimSortを使用しておりO(nlogn)、SortedList()はO(nlogn)で動く(なんのソートかは探し出せなかった) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. SortedList はたしか非標準でしたね。 https://docs.python.org/3/library/heapq.html#heapq.heappushpop There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 豆知識ですが、3.11からpowersortが使われているみたいですね。 |
||
|
||
# step3 | ||
```python | ||
class KthLargest: | ||
|
||
def __init__(self, k: int, nums: List[int]): | ||
self.k = k | ||
self.k_largest_nums = [] | ||
|
||
for num in nums: | ||
self.add(num) | ||
|
||
def add(self, val: int) -> int: | ||
heapq.heappush(self.k_largest_nums, val) | ||
|
||
while self.k < len(self.k_largest_nums): | ||
heappop(self.k_largest_nums) | ||
|
||
return self.k_largest_nums[0] | ||
``` |
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.
関数を呼び出す側としては、ある関数を呼び出したときに、渡した引数の中身が変更されることは、あまり想定しないように思います。関数内では原則引数の中身を変更しないことをお勧めいたします。また、特別な理由があって変更する場合は、関数コメント等に明示的にその旨を書くことをお勧めいたします。