Skip to content

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
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 99 additions & 0 deletions lc703.md
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)
Copy link

Choose a reason for hiding this comment

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

関数を呼び出す側としては、ある関数を呼び出したときに、渡した引数の中身が変更されることは、あまり想定しないように思います。関数内では原則引数の中身を変更しないことをお勧めいたします。また、特別な理由があって変更する場合は、関数コメント等に明示的にその旨を書くことをお勧めいたします。


i = 0
Copy link

@nodchip nodchip Dec 8, 2024

Choose a reason for hiding this comment

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

self.sorted_nums = nums[-k:] でよいと思います。

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:
Copy link

Choose a reason for hiding this comment

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

- の両側にスペースを空けることをお勧めいたします。

https://peps.python.org/pep-0008/#other-recommendations

Always surround these binary operators with a single space on either side: assignment (=), augmented assignment (+=, -= etc.), comparisons (==, <, >, !=, <>, <=, >=, in, not in, is, is not), Booleans (and, or, not).

https://google.github.io/styleguide/pyguide.html#36-whitespace

Use your better judgment for the insertion of spaces around arithmetic operators (+, -, *, /, //, %, **, @).

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)で動く(なんのソートかは探し出せなかった)
Copy link

Choose a reason for hiding this comment

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

SortedList はたしか非標準でしたね。

https://docs.python.org/3/library/heapq.html#heapq.heappushpop
あと、heapq のドキュメントを見ておきましょう。(これからも、なにか標準関数を呼ぶ時、ドキュメントを読んだ記憶がなければ開いて読んでみてください。)
heappushpop, heapreplace などがあります。

Choose a reason for hiding this comment

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

豆知識ですが、3.11からpowersortが使われているみたいですね。
https://www.i-programmer.info/news/216-python/15954-python-now-uses-powersort.html


# 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]
```