Skip to content
Open
Show file tree
Hide file tree
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
67 changes: 67 additions & 0 deletions problems/347.top-k-frequent-elements/memo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
## step1
- pythonのCounterでできないのか?
- Counter.most_common()でできそう
- https://github.com/python/cpython/blob/a8e814db96ebfeb1f58bc471edffde2176c0ae05/Lib/collections/__init__.py#L571
- 内部で_heapq.nlargestを使っており、計算量はO(nlogk)

```py
for num, _count in counter.most_common():
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

確かに、たとえばPEP8ではcountが予約語ならcount_のようによける書き方がありますが、countは予約語では無いのでそのまま書いて大丈夫かなと思いました。

If a function argument’s name clashes with a reserved keyword, it is generally better to append a single trailing underscore rather than use an abbreviation or spelling corruption. Thus class_ is better than clss. (Perhaps better is to avoid such clashes by using a synonym.)

https://peps.python.org/pep-0008/#function-and-method-arguments

あるいは使わないループ変数という意図であれば_で潰すと良いと思います。

frequent_nums.append(num)
if len(frequent_nums) == k:
break
Comment on lines +8 to +11
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Counter.most_common()メソッドのオプショナルな引数nで上位n個だけにできるので、使うとif-breakのところが無くせてシンプルです。

Suggested change
for num, _count in counter.most_common():
frequent_nums.append(num)
if len(frequent_nums) == k:
break
for num, _count in counter.most_common(k):
frequent_nums.append(num)

https://docs.python.org/3/library/collections.html#collections.Counter.most_common

こう書くなら、内包表記にしてもいいですね。趣味の範囲です。

class Solution:
    def topKFrequent(self, nums: List[int], k: int) -> List[int]:
        counter = Counter(nums)
        return [num for num, _ in counter.most_common(k)]

```
- 上記のように書いたが、forのindexをとるときは普段enumerateを使うようにしているが、今回の場合は下記のようになり少しわかりにくいかなと思って上記にした
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

自分も上の方がわかりやすいと感じます。

簡単なものさしとして、変数は減らせるだけ減らすのはわりと有効な気がします。(もちろん例外もありますが。)


```py
for index, (num, _count) in enumerate(counter.most_common()):
frequent_nums.append(num)
if index == k - 1:
break

return frequent_nums
```

## step2
自分としては気になるところはないので、他の人のコードを見る
- https://github.com/Hiroto-Iizuka/coding_practice/pull/9/files
- Counterだと使うだけなので出題意図と沿っていないかも
Copy link
Copy Markdown

@mamo3gr mamo3gr Jan 7, 2026

Choose a reason for hiding this comment

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

出題意図と沿っていない

というより、じゃあ Counter 実装してみてください、という話になるのだと思います。
(でstep2ではそうできています)

- defaultdictに入れてvalueでkeyをsortして出すのも良いかも
- dictの命名は大抵の場合key_to_valueがわかりやすい!!!
- https://github.com/mamo3gr/arai60/pull/9/files
- コメント集のまとめが勉強になった
- コメント集をどのstepで読むか迷うがどこかでは読みたい
- `sorted(num_count, key=num_count.get)`の書き方は初めて見た。。。毎回lambda式を調べていた
- https://github.com/Yuto729/LeetCode_arai60/pull/15/files
- step2のheapのとこは文言で見ると難しそうでわかんなかった
- https://github.com/naoto-iwase/leetcode/pull/9/files
- 上のさっきのstep2解法だと思うが、見たらわかりやすかった
- 大きい順だと対応できないので-をつけてやる方法は`min-heap`という名前がついてるみたい
- `defaultdictではなく[Counter](https://docs.python.org/ja/3.13/library/collections.html#collections.Counter)のが適していそう。そう思う理由は今のところ、カウント用途に特化したクラスだから良さそう、というくらいしかない。`
- 自分は出現回数を数えるといえばと思ってほぼ何も考えず飛びついてしまったので何で適しているかは言語化していきたい
- クイックソートについて知っていなくてはいけないことは下記のようだが、計算量がO(NlogN)であることしか知らない。。。
- 最悪・平均計算量
- 末尾再帰最適化
- ピボット選択
- マージソートとのプロコン
- このかたのmemoはすごいが、自分の力量だとここまですると1問につき1年かかるので、1周したあとまた見にくる
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

私、「マージソートとのプロコン」という言葉に、ソートの安定性やメモリーアクセスの局所性などを詰め込んでいます。本当は、中身を詳しく書いたほうがいいですね。

- https://github.com/t-ooka/leetcode/pull/15/files
- たくさんの解法がおさえてありすごい
- いくつか自分も思いついた際は書けるようにしたい

- defaultdictを使った解放にする
- 時間計算量はmをユニークな要素数としてO(n) + O(mlogm)
- 最悪時間計算量はO(nlogn)(ほぼmがnになるので)
- 空間計算量はO(m)

## step3
- defaultdictの初期値(今回はint)を忘れない
- key=~getの書き方はすっきりしているので毎回調べず書けるようになりたい



## TODO
[] クイックソートについて
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

コーディング練習会の本筋ではないですが、Markdownのチェックボックスは箇条書きでないとレンダリングされないようです。

Suggested change
[] クイックソートについて
- [] クイックソートについて

- 最悪・平均計算量
- 末尾再帰最適化
- ピボット選択
- マージソートとのプロコン
23 changes: 23 additions & 0 deletions problems/347.top-k-frequent-elements/step1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#
# @lc app=leetcode id=347 lang=python3
#
# [347] Top K Frequent Elements
#
from collections import Counter


# @lc code=start
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
counter = Counter(nums)
frequent_nums = []

for num, _count in counter.most_common():
frequent_nums.append(num)
if len(frequent_nums) == k:
break

return frequent_nums


# @lc code=end
24 changes: 24 additions & 0 deletions problems/347.top-k-frequent-elements/step2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#
# @lc app=leetcode id=347 lang=python3
#
# [347] Top K Frequent Elements
#

from collections import defaultdict


# @lc code=start
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
num_to_frequency = defaultdict(int)
for num in nums:
num_to_frequency[num] += 1

num_frequent_order = sorted(
num_to_frequency, key=num_to_frequency.get, reverse=True
)

return num_frequent_order[:k]


# @lc code=end
24 changes: 24 additions & 0 deletions problems/347.top-k-frequent-elements/step3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#
# @lc app=leetcode id=347 lang=python3
#
# [347] Top K Frequent Elements
#

from collections import defaultdict
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[fyi]
(まだでしたら)インポートの流儀も気にすると良いかもしれません。

例えばGoogleのスタイルガイドでは、ここでは import collections が推奨されているように読めます。
https://google.github.io/styleguide/pyguide.html#22-imports

Use import statements for packages and modules only, not for individual types, classes, or functions.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

もちろんGoogleのスタイルガイドが絶対ではありません。メリット・デメリットを把握しつつ、自分が取るスタイルを決めると良いと思います。

(私も個人的には、コード本体が長くなりがちなのでこのような短いimportの方が好きです)



# @lc code=start
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
num_to_frequency = defaultdict(int)
for num in nums:
num_to_frequency[num] += 1

num_frequency_order = sorted(
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

細かくて恐縮ですが、英語的に _ordered がより適切に感じました。_order という名前だけ見ると、ソート後のインデックスが入っているようにも読めるので

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

たしかに、nums_ordered_by_frequencyとかだとかなり丁寧な印象ですね。

num_to_frequency, key=num_to_frequency.get, reverse=True
)

return num_frequency_order[:k]


# @lc code=end