Pythonで最も頻出する上位K個の要素を求めるアルゴリズムを解説
問題概要
空ではない整数型の配列が与えられたとき、その中で最も頻繁に出現する上位k個の要素を返すことを考えます。
例えば、要素が [1,1,1,1,2,2,3,3,3] で k = 2 の場合、結果は [1, 3] となります。
解法のアプローチ
この問題は、ハッシュマップ(辞書)を2つ使うことで効率的に解くことができます。全体の流れは以下の通りです。
- 出現回数の記録: 各数値の出現回数を最初のマップに記録します。
- 頻度ごとのグループ化: 「出現回数」をキー、「その回数で出現した数値のリスト」を値とする2つ目のマップを作成します。
- 頻度の高い順に抽出: 配列の長さから降順にループし、該当する頻度の要素を結果リストへ追加していきます。
- 早期終了: 結果リストの長さがk以上になった時点でループを抜けます。
具体的な手順
- num_freq(空のマップ)と freq_list(空のマップ)を用意します。
- nums の各要素 i について、i が num_freq に存在しなければ num_freq[i] := 1 とし、存在すれば num_freq[i] を1増やします。
- num_freq の各キー・バリューのペアについて、value が freq_list に存在しなければ freq_list[value] := [key] とし、存在すれば freq_list[value] のリストに key を挿入します。
- res := 空のリストとします。
- i を配列の長さから 0 まで減らしながらループし、i が freq_list に存在すれば freq_list[i] の要素を res に追加します。
- res の長さが k 以上になったら break します。
- 結果を返します。
Pythonでの実装例
それでは、理解を深めるために実際のコードを見てみましょう。
class Solution(object):
def topKFrequent(self, nums, k):
number_frequency = {}
frequency_list = {}
for i in nums:
if i not in number_frequency:
number_frequency[i] = 1
else:
number_frequency[i] += 1
for key, value in number_frequency.items():
if value not in frequency_list:
frequency_list[value] = [key]
else:
frequency_list[value].append(key)
result = []
for i in range(len(nums), 0, -1):
if i in frequency_list:
result.extend(frequency_list[i])
if len(result) >= k:
break
return result
ob1 = Solution()
print(ob1.topKFrequent([1,1,1,1,2,2,3,3,3], 2))
入力
[1,1,1,1,2,2,3,3,3] 2
出力
[1, 3]
計算量について
このアルゴリズムの時間計算量は O(n) です(n は配列の長さ)。出現回数のカウントに O(n)、頻度ごとのグループ化にも O(n)、最後のループは最大でも O(n) で完了します。空間計算量も同様に O(n) となります。ソートベースの手法(O(n log n))と比べて高速に動作する点が大きな特徴です。
-
Pythonのリストで連続する要素をペアにする方法
Pythonでデータ分析を行っていると、リスト内の隣接する(連続する)要素同士をペアとして取り出したい場面に出会うことがあります。本記事では、この処理を実現するための代表的な2つの方法を、サンプルコードとともにわかりやすく解説します。インデックスとrangeを組み合わせる方法まずは、リストの連続するインデックスを組み合わせてペアを作る式を設計する方法です。range関数に「リストの長さ − 1」を渡すことで、ペアリングを繰り返す最大回数を決定します。これにより、最後の要素にアクセスする際に範囲外エラーが発生するのを防いでいます。サンプルコードlistA = [51,23,11,45] # 対象
-
Pythonでリストから指定したインデックスの複数要素を削除する方法
Pythonのリストから単一の要素を削除するのは、del文とインデックスを組み合わせれば簡単に行えます。しかし、複数のインデックスに該当する要素をまとめて削除したいケースでは、少し工夫が必要です。本記事では、削除対象となるインデックスのリストを指定して、元のリストから該当する要素だけを取り除く方法を2つ紹介します。方法1:sorted()とdelを組み合わせるこのアプローチでは、まず削除したい位置(インデックス)を格納したリストを作成します。その後、降順にソートしてから後ろの要素から順に削除することで、削除処理中にインデックスがずれる問題を回避し、元のリストの構造を保ったまま安全に要素を削除で