Conversation
| ```python | ||
| class Solution: | ||
| def topKFrequent(self, nums: List[int], k: int) -> List[int]: | ||
| occurrences: dict[Tuple(int, int)] = {} |
There was a problem hiding this comment.
Type Hintが違うような気がします。 dict[int, int]かなと。
https://docs.python.org/3/library/typing.html#generics
There was a problem hiding this comment.
ご指摘ありがとうございます。間違ってますね。
| frequencyを数える->frequencyを降順にソートする->値の大きいものから取り出してリストを作成が基本的な流れだと思った。 | ||
|
|
||
| frequencyを数える作業をどうするか迷った。とりあえず思いついたのは、与えられた`nums`をソートして | ||
| それに対してループで走査してfrequencyを数える方法。`nums`が与えられているので、`sorted_numbers`ではなく`sorted_nums`と略しても許容範囲かと判断した。与えられた`nums`からfrequencyを数える時にも、frequencyの大きいものを順に取り出す時にもheapは使えるが、計算量が変わらない上にpythonのデフォルトはmin-heapなので`(-1 * number_of_appears, number)`にする必要があり、複雑に感じたので使わなかった。 |
There was a problem hiding this comment.
計算量が変わらない上にpythonのデフォルトはmin-heapなので
(-1 * number_of_appears, number)にする必要があり、複雑に感じたので使わなかった。
min-heap を max-heap として無理やり使うのが複雑であるというのは僕も同意です。(今回は使用しないという判断なので関係ないですが)仮に使う場合はコメントを残すことは必須かなと個人的には思っています。
| if num not in occurrences: | ||
| occurrences[num] = 1 | ||
| else: | ||
| occurrences[num] += 1 |
There was a problem hiding this comment.
以下書き方のほうが個人的には好きです。
| if num not in occurrences: | |
| occurrences[num] = 1 | |
| else: | |
| occurrences[num] += 1 | |
| if num not in occurrences: | |
| occurrences[num] = 0 | |
| occurrences[num] += 1 |
| while index < len(sorted_nums) and sorted_nums[index] == number: | ||
| index += 1 | ||
| number_of_appears += 1 | ||
| frequency.append((number_of_appears, number)) |
There was a problem hiding this comment.
個人的な好みのお話で、ここの while - while について他の書き方もしてみたくなりました。
下記、ループの外側で最後の追加をしていて微妙ですが、こんな感じにも書けそうです。
if len(sorted_nums) == 0:
return []
number: int = sorted_nums[0]
number_of_appears: int = 1
for i in range(1, len(sorted_nums)):
if sorted_nums[i] == number:
number_of_appears += 1
continue
frequency.append((number_of_appears, number))
number = sorted_nums[i]
number_of_appears = 0
frequency.append((number_of_appears, number))There was a problem hiding this comment.
コメントありがとうございます。
こちらの方はネストが少ない分の読みやすさがありますね。
| occurrences[num] += 1 | ||
| ``` | ||
| - dictを用いない場合では、Counterを使い、`most_common`を呼び出す。 | ||
| https://docs.python.org/3/library/collections.html#collections.Counter |
There was a problem hiding this comment.
いいですね。
せっかくなので実装も見ておきましょう。何を使っていて自分のと比べてどう思いますか。
https://github.com/python/cpython/blob/main/Lib/collections/__init__.py
There was a problem hiding this comment.
共通点
- Counterもdefaultdictもdict class(hash tableで実装)を継承している。
相違点
- keyが存在しない時にCounterは0を返すが、defaultdictは与えられた型でのデフォルトコンストラクタを呼び出す。もし型の指定がなければ、Noneを返す。
- Counterのmost_commonについては、heapq.nlargestを使っている。
- defaultdictを使った今回の自分の解法では、新たにheapを用意して、heapq.heappopとheapq.heappushを繰り返して、指定された要素数だけ値が収まる様にしている。
思ったこと
今回は数字の出現頻度を数える問題だったので、それに特化したCounterの方が余計にheapを用意する必要もなく、見やすい様に感じました。
ただ、もともと用意されているCounterのmethodを用いた実装と、defaultdictで足りない出現頻度の高い値を求める部分を自分でheapを使って調べた実装とでやっていることがそう大きくは変わらない印象も受けました。
| num_to_count[num] += 1 | ||
|
|
||
| if not 0 < k <= len(num_to_count): | ||
| raise ValueError( |
There was a problem hiding this comment.
https://docs.python.org/3/library/exceptions.html#ValueError
時々、どのような Exception が定義されているか眺めてみましょう。
https://leetcode.com/problems/top-k-frequent-elements/description/