1. [1,2,2,3,3] -> 2 (tie smallest)
  2. [5,5,5,1,2] -> 5
  3. [7] -> 7
  4. [1,2,3] -> 1 (all tied, smallest)
  5. [4,4,3,3,2,2] -> 2 (3-way tie)
  6. [10,20,10,20,10] -> 10
コース一覧
コンピューターサイエンス上級:アルゴリズムとデータ構造
hashmap で頻度集計

コンピューターサイエンス上級:アルゴリズムとデータ構造

探索、ソート、木、グラフ、動的計画法、貪欲法など、競技プログラミングや技術面接で問われる高度なアルゴリズムとデータ構造を学べるコースです。基本的な CS の知識を持ち、アルゴリズム力を伸ばしたい学習者や、外資・大手の技術面接対策をしたい方を対象としています。約 13 時間 (1 日 30 分 × 26 日) で 50 レッスンを修了でき、修了後はコーディング面接の実装問題を構造的に解けるようになります。

1
連結リスト
01. リンクリスト構築と長さの計算5分
02. リンクリストの反転5分
03. リンクリストのサイクル検出5分
04. ソート済みリンクリストの merge5分
05. リンクリストの中央ノード取得5分
06. ソート済みリストの重複削除5分
07. 第1章まとめクイズ5分
2
二分木
01. 二分木の in-order 走査5分
02. 二分木の pre-order 走査5分
03. 二分木の post-order 走査5分
04. 二分木の幅優先走査 (BFS)5分
05. 二分木の高さ5分
06. 二分木の平衡判定5分
07. 第2章まとめクイズ — 二分木5分
3
探索木 (BST)
01. BST に値を挿入する5分
02. BST から値を検索する5分
03. BST の最小値と最大値5分
04. BST 妥当性チェック5分
05. BST で k 番目に小さい値5分
06. BST から値を削除する5分
07. 第 3 章 まとめクイズ5分
4
ハッシュとセット
01. hashmap で頻度集計5分
02. キーでグループ化5分
03. two sum (hash で O(n))5分
04. 部分配列の和 = k の個数5分
05. 最長連続部分列5分
06. 集合の積 (intersection)5分
07. 第4章まとめクイズ5分
5
グラフ
01. グラフ BFS で連結成分サイズを求める5分
02. グラフ DFS で連結成分の数を数える5分
03. グラフのパス存在判定5分
04. BFS で最短経路の長さを求める5分
05. トポロジカルソート5分
06. 2 部グラフ判定5分
07. ダイクストラ法 — 重み付きグラフの最短経路15分
08. 第5章まとめクイズ — グラフ5分
6
動的計画法 (上級)
01. 編集距離 (レーベンシュタイン距離)5分
02. 最長増加部分列(LIS)の解法 ── AOJ 2430 対応の動的計画法5分
03. 最大部分配列和 (Kadane)5分
04. 隣り合わない最大値 (House Robber)5分
05. グリッド経路数 (Unique Paths)5分
06. 単語分割可能か (Word Break)5分
07. 第6章まとめクイズ — 動的計画法 (上級)5分
7
総合データ構造と関数型
01. map と filter を組み合わせる5分
02. reduce で積を計算5分
03. 関数合成5分
04. カリー化5分
05. trie の単純検索 (prefix マッチ)5分
06. Union-Find (連結成分数)5分
07. 最終総まとめクイズ5分

hashmap で頻度集計

1 万件を数えるのに、1 億回比べている

配列の中で一番多く出てくる値を知りたいとします。素直に書くと、値を 1 つ取り出して「この値は何回出てくるか」を配列全体を歩いて数え、それを全要素ぶん繰り返す形になります。

要素が 100 個なら 1 万回、1 万個なら 1 億回。数えている相手はずっと同じ配列なのに、同じ場所を何度も歩き直しています。

紙を 1 枚だけ持って、1 周で終わらせる

人が手で数えるときは、正の字を書く紙を 1 枚だけ持って、上から順に 1 回読むだけです。同じことをプログラムでやります。正の字を書き込む紙にあたるのが hashmap で、Python なら dict、JavaScript なら Map がそれです。

Python

# 別題材 — ログのエラーコードを数える tally = {} for code in codes: tally[code] = tally.get(code, 0) + 1

大事なのは get(code, 0) の 0 です。初めて見るコードには、まだ欄がありません。tally[code] + 1 と書くと Python はその場でエラーになり、JavaScript では undefined + 1 が NaN になって、以後ずっと数が壊れたままになります。「無ければ 0 から」を最初に書いてください。

JavaScript

tally.set(code, (tally.get(code) || 0) + 1);

これで、要素が 1 万個でも 1 万回で表が埋まります。

1 周で済むのは、表から欄を引くのに端から探す必要がないからです。値そのものが置き場所を決めるので、欄が 1 万件に増えても引く速さは変わりません。数える相手も整数に限りません。文字列でも同じ形なので、単語の出現回数もエラーコードの集計も、書くコードはほとんど同じになります。

数え終わってから、選ぶところで詰まる

表ができたら、一番大きい数の行を選びます。手が止まるのは、同じ回数の行が 2 つ以上あったときです。[4, 4, 3, 3, 2, 2] を数えると、こうなります。

値回数
42
32
22

3 つとも 2 回で並んでいます。どれを返すか決めていないと、表から取り出す順しだいで答えが変わります。しかも、その順は言語や実装によって違います。手元では通ったのに提出したら落ちる、という形で表に出てくるので厄介です。

今回は同点なら小さいほうの値を返す約束です。選ぶ側の条件には、回数の比較と値の比較の 2 つが要ります。回数だけを見ていると、同点のときに先に見た行が残ってしまいます。

空の配列に最頻値はない

要素が 1 つも無ければ、一番多い値は決められません。今回は -1 を返します。空の表に対して「一番大きい行」を探しても何も見つからないので、初期値がそのまま返ります。配列の長さを先に見て、分けてしまうのが確実です。

要件

  1. 配列は最大数千要素まで対応すること
  2. 二重ループ (O(n^2)) ではなく hashmap を使った O(n) で実装する
  3. 頻度が同じ値が複数ある場合は、その中で最も小さい値を返す。空配列なら -1 を返す

入出力例

mostFrequent([1,2,2,3,3]) → 2 mostFrequent([5,5,5,1,2]) → 5 mostFrequent([7]) → 7 mostFrequent([1,2,3]) → 1 mostFrequent([4,4,3,3,2,2]) → 2 mostFrequent([10,20,10,20,10]) → 10

ヒント

Python なら `dict.get(v, 0) + 1`、JS なら `(map.get(v) || 0) + 1` で安全にインクリメント

最頻値を求める走査では `count > best_count` だけでなく `count == best_count and value < best_value` も比較する

空配列のチェックを最初に書いておくと、後段のロジックが綺麗になる

生田 陸人
監修生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア監修者プロフィールを見る →
編集 ゆめさく編集部·公開 2026/05/19·更新 2026/08/26

関連レッスン

  • キーでグループ化

    整数配列を 2 で割った余りでグループ化し、`[偶数のソート済みリスト, 奇数のソート済みリスト]` の形で返す。

  • two sum (hash で O(n))

    整数配列と目標値 `target` を受け取り、和が `target` になる 2 要素のインデックスをソート済みリストで返す。

  • 部分配列の和 = k の個数

    整数配列と `k` を受け取り、和が `k` になる **連続する部分配列** の個数を `hashmap` と累積和で `O(n)` で数える。

  • 最長連続部分列

    整数配列を `set` に入れて、連続する整数で最も長いシーケンスの長さを `O(n)` で求める。

このレッスンに出てくる用語

意味があいまいなまま進んだ語は、ここから読み直せます。

  • 配列サイズ固定の同型データの集まり
  • JavaScriptWeb で動的な振る舞いを担う言語
  • ループ繰り返し処理。矢印で戻すか専用記号で示す
main.py
学習モード
エディタを読み込んでいます

メモ

hashmap で頻度集計

⌘S で保存