1. 5 nodes, 2 components
  2. 5 nodes, all connected
  3. 4 nodes with self-loop -> 4
  4. single node self-loop
  5. 6 nodes, 3 components
  6. redundant edges
コース一覧
コンピューターサイエンス上級:アルゴリズムとデータ構造
Union-Find (連結成分数)

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

探索、ソート、木、グラフ、動的計画法、貪欲法など、競技プログラミングや技術面接で問われる高度なアルゴリズムとデータ構造を学べるコースです。基本的な 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分

Union-Find (連結成分数)

報告が 1 件届くたびに、全体を歩き直したくない

利用者アカウントが 6 件あり、「この 2 つは同一人物でした」という報告が 1 件ずつ届きます。届くたびに「今いくつのグループに分かれているか」を答えたい。報告のたびに全体をたどり直すと、報告の数だけ全員を歩くことになります。しかも歩く先は、前回とほとんど同じ場所です。

しかし、ここで知りたいのは経路ではありません。「同じ組かどうか」だけです。それなら、組ごとに代表を 1 人決めておけば足ります。

代表を 1 人決める

各要素に「親」を 1 つだけ持たせます。最初は全員が自分自身を親にしていて、これは「全員が別の組」という状態です。

JavaScript

const parent = [0, 1, 2, 3, 4, 5];

代表を聞かれたら、親をたどって、自分自身が親になっているところまで登ります。そこが組の代表です。途中に何件はさまっていても、行き着く先が同じなら同じ組です。2 つを同じ組にするときは、まずそれぞれの代表まで登り、片方の代表の親を、もう片方の代表にします。付け替えるのは代表 1 つだけで、組の中の全員を書き換える必要はありません。

報告が 3 件届いたときの親の並びは、次のように変わります。

状態012345
最初012345
0 と 2 が同一212345
4 と 5 が同一212355
2 と 3 が同一213355

最後に全員の代表を聞くと、0 と 2 と 3 は代表が 3、4 と 5 は代表が 5、1 は自分のままです。数えるのは人数ではなく代表の種類なので、組は 3 つです。誰とも結ばれなかった 1 も、自分が代表のまま 1 組として数えられます。

すでに同じ組の 2 つを結ぶ報告や、自分自身への報告が来ることもあります。代表が同じなら何もしない、という分岐を入れておけば、そのまま素通しできます。

この持ち方が向くのは、つながりが後から 1 本ずつ増えていく場面です。つながりが最初から全部そろっていて、数えるのが 1 回きりなら、探索で数えても手間は変わりません。報告が届くたびに答えたい、という状況ではじめて差がつきます。

たどる道を短くしておく

この仕組みの弱点は、つなぎ方によって親の鎖が長くなることです。一直線に伸びてしまうと、代表を聞くたびに端から端まで登ることになり、せっかくの速さが出ません。

工夫は 1 つ入れれば十分です。代表を聞かれてたどったついでに、通ったところの親を代表に付け替えておきます。次からは 1 歩で代表に着くので、同じ場所を何度も登らずに済みます。答えは何も変わらず、たどる距離だけが縮みます。代表を聞くほど道が整理されるので、使い込むほど速くなる、という珍しい形の工夫です。

解説

覚え方 ... 代表が同じなら同じ組。組を数えるのは、代表の種類を数えること。

要件

  1. parent 配列で各ノードの代表元を管理する Union-Find を実装する
  2. find は親を辿ってルートを返す。path compression を入れると効率的
  3. 最後にユニークなルート数を数えて返す

入出力例

countComponents(5, [[0,1],[1,2],[3,4]]) → 2 countComponents(5, [[0,1],[1,2],[2,3],[3,4]]) → 1 countComponents(4, [[0,0]]) → 4 countComponents(1, [[0,0]]) → 1 countComponents(6, [[0,1],[2,3],[4,5]]) → 3 countComponents(4, [[0,1],[1,2],[0,2]]) → 2

ヒント

初期状態は parent[i] = i (全員が自分自身を親とする)

辺 (a, b) を見たら find(a) と find(b) のルートを取って、異なれば parent[ra] = rb で繋ぐ

最後に全ノードに対して find(i) を呼び、ユニークなルート数を set で数える

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

関連レッスン

  • 最終総まとめクイズ

    cs-system-design コース全体の総まとめクイズ。連結リスト、二分木、BST、ハッシュ、グラフ、動的計画法、関数型の知識を確認する。

  • trie の単純検索 (prefix マッチ)

    単語の集合に対して `trie` を構築し、与えられたプレフィックスで始まる単語が存在するかを判定する関数を実装する。trie の基本構造とプレフィックスマッチを学ぶ。

  • カリー化

    2 引数の関数を 1 引数の関数のチェーン `f(a)(b)` に変換するカリー化を内部で組み立てて適用する。`add(a, b)` をカリー化して `add(a)(b)` の形で呼び出した結果を返す関数を実装する。

  • 関数合成

    `compose(f, g)(x) = f(g(x))` の関数合成を関数の中で組み立てて適用する。`addOne` と `double` を合成して値に適用した結果を返す関数を実装する。

main.py
学習モード
エディタを読み込んでいます

メモ

Union-Find (連結成分数)

⌘S で保存