C++でTop Kの頻出単語を抽出するアルゴリズムの解説
問題の概要
空でない単語のリストが与えられたとき、出現頻度の高い上位k個の単語を見つける問題を考えてみましょう。答えは頻度の高い順(降順)にソートされている必要があります。また、2つの単語の頻度が同じ場合は、アルファベット順で先に来る単語を先に配置します。
例えば、配列が ['the', 'sky', 'is', 'blue', 'the', 'weather', 'is', 'comfortable'] の場合、最も頻出する単語は ["is", "the", "blue"] となります。
解決手順
この問題を解くには、以下の手順に従います。
- マップ
mを1つ定義する - 優先度付きキュー
vを1つ作成する - i を 0 から n(単語配列のサイズ)まで繰り返し、
m[words[i]]を1ずつ増やす - マップ内の各要素 e について以下を処理する
vのサイズが k 未満であれば、e をvに挿入する- そうでなく、
v.top()の頻度値が e の頻度値より小さい場合は、vから先頭要素を削除して e を挿入する - そうでなく、
v.top()の頻度値が e の頻度値と等しく、かつv.top()のキー(単語)が e のキーより大きい(アルファベット順で後)場合は、vから先頭要素を削除して e を挿入する
- 配列
resを1つ定義する vが空でない間、以下を繰り返す- temp に
vの先頭要素を代入する vから先頭要素を削除する- temp のキー(単語)を
res配列に挿入する
- temp に
res配列を反転するresを返す
C++での実装例
理解を深めるために、以下の実装例を見てみましょう。
#include <bits/stdc++.h>
using namespace std;
void print_vector(vector<auto> v){
cout << "[";
for(int i = 0; i<v.size(); i++){
cout << v[i] << ", ";
}
cout << "]"<<endl;
}
struct Comparator{
bool operator()(pair <string ,int> a, pair <string, int> b){
if(a.second != b.second) return !(a.second < b.second);
return !(a.first > b.first);
}
};
class Solution {
public:
static bool cmp(pair <string, int> a, pair <string, int> b){
if(a.second != b.second) return a.second > b.second;;
return a.first < b.first;
}
vector<string> topKFrequent(vector<string>& words, int k) {
map<string, int> m;
priority_queue < pair <string, int>, vector < pair <string, int> >, Comparator > v;
for(int i = 0; i < words.size(); i++){
m[words[i]]++;
}
map<string, int> :: iterator i = m.begin();
while(i != m.end()){
if(v.size() < k){
v.push(*i);
}
else if(v.top().second < i->second){
v.pop();
v.push(*i);
}
else if(v.top().second == i->second && v.top().first > i->first){
v.pop();
v.push(*i);
}
i++;
}
vector <string> res;
while(!v.empty()){
pair <string, int> temp = v.top();
v.pop();
res.push_back(temp.first);
}
reverse(res.begin(), res.end());
return res;
}
};
main(){
Solution ob;
vector<string> v = {"the", "sky", "is", "blue", "the", "weather", "is", "comfortable"};
print_vector(ob.topKFrequent(v, 3));
}入力
["the", "sky", "is", "blue", "the", "weather", "is", "comfortable"] 3
出力
["is","the","blue"]
アルゴリズムのポイント
この実装では、まず map を使って各単語の出現回数をカウントします。次に、カスタムコンパレータを持つ priority_queue を利用することで、頻度が低い単語やアルファベット順で後ろの単語を効率的にキューの先頭に保持できます。これにより、キューのサイズを k に制限しながら、頻度上位 k 個の単語だけを残すことが可能になります。
最後にキューから要素を取り出して配列に格納し、反転することで頻度の降順かつアルファベット昇順の結果を得られます。計算量は、単語数を n、異なる単語数を m とすると、O(n + m log k) となり、効率的な処理が実現できます。
-
Windowsで使えるC++開発向けおすすめIDE 7選
```html 大規模なプロジェクトをプレーンなテキストエディターだけで管理するのは困難です。こうしたケースではIDE(統合開発環境)を使った方が、生産性が向上しストレスも大幅に軽減されます。IDEにはさまざまな種類があり、自分のニーズに合ったものを選ぶことが重要です。ここでは、Windowsで利用できる優れたC/C++向けIDEをご紹介します。 1. Visual Studio Microsoftが開発した定番IDEです。Windows上でのC++プログラムの構築・開発・プロファイリングにおいて、最高クラスのツール群を備えています。豊富なプラグインストアも魅力で、Azure、PowerShe
-
Pythonで最も頻出する上位K個の要素を求めるアルゴリズムを解説
問題概要 空ではない整数型の配列が与えられたとき、その中で最も頻繁に出現する上位k個の要素を返すことを考えます。 例えば、要素が [1,1,1,1,2,2,3,3,3] で k = 2 の場合、結果は [1, 3] となります。 解法のアプローチ この問題は、ハッシュマップ(辞書)を2つ使うことで効率的に解くことができます。全体の流れは以下の通りです。 出現回数の記録: 各数値の出現回数を最初のマップに記録します。 頻度ごとのグループ化: 「出現回数」をキー、「その回数で出現した数値のリスト」を値とする2つ目のマップを作成します。 頻度の高い順に抽出: 配列の長さから降順にループし、該当する