1. [1,2,3] -> false
  2. [1,2,3,2] -> true
  3. [1] -> false
  4. [5,5] -> true
  5. [1,2,3,4,5] -> false
  6. [1,2,3,4,3] -> true
コース一覧
コンピューターサイエンス上級:アルゴリズムとデータ構造
リンクリストのサイクル検出

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

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

リンクリストのサイクル検出

末尾のノードの next が、うっかりリストの途中を指してしまうことがあります。見た目はいつものリストです。ところが、たどり始めると二度と終わりません。

たどり始めたら、いつまでも終わらない

Python

cur = head while cur is not None: print(cur.value) cur = cur.next

このループは next が空になった時点で止まります。途中のノードへ戻る札が 1 枚でもあると、その先はぐるぐる回り続け、空には永久に届きません。ログが出続けるか、無言のまま固まるかのどちらかです。輪があるかどうかを、たどる前に知りたくなります。

速さの違う 2 つを走らせる

対処法は少し変わった形をしています。同じ先頭から 2 つの目印を出し、片方は 1 歩ずつ、もう片方は 2 歩ずつ進めます。

Python

def has_loop(head): slow = head fast = head while fast is not None and fast.next is not None: slow = slow.next fast = fast.next.next if slow is fast: return True return False

輪が無ければ、速いほうが先に末尾を突き抜けて while が終わります。輪があれば、2 つは必ず同じノードで重なります。追加で使うメモリは、変数 2 つぶんだけです。

なぜ必ず追いつくのか

輪に入るまでの間は、2 つの差はどんどん開いていきます。ただ、速いほうが先に輪へ入るので、遅いほうが輪に着いたときには、相手はすでに輪の中を回っています。ここから先が本番です。

2 つとも輪の中に入ってしまえば、あとは追いかけっこです。1 回進むごとに、速いほうは 2 マス、遅いほうは 1 マス動くので、2 つの差はちょうど 1 マスずつ縮みます。

縮み方が 1 ずつなので、差が 0 を飛び越えることはありません。輪の長さを L とすれば、遅くとも L 回以内に差は 0 になり、2 つは同じノードに立ちます。これが「必ず出会う」の中身です。

速いほうを 3 歩にすると壊れます。差は 2 ずつ縮むので、L が偶数で差が奇数のときは 0 を素通りし、いつまでもすれ違い続けます。1 歩と 2 歩という組み合わせに意味があるわけです。

輪ができるのはリストだけではありません。モジュールの import が A から B、B から A と戻っていれば、依存をたどるビルドツールは同じところを回り続けます。だから依存を解決する側には、たいてい輪の検出が組み込まれています。たどる前に輪を疑う、という発想はどのデータ構造でも同じです。

訪れた場所を全部記録しておいて、2 度目に来たら輪あり、と判定する手もあります。分かりやすい代わりに、ノード数ぶんのメモリを使います。今回の課題はその記録する側で書きますが、記録の順番だけ気をつけてください。先に記録してから照合すると、必ず自分自身に当たって、どんな入力でも輪ありになります。

要件

  1. 連結リストは配列 arr で表現する
  2. 値の重複を hash set で検出し、O(n) で判定する
  3. 重複があれば true (boolean) を、なければ false を返す

入出力例

hasCycle([1,2,3]) → false hasCycle([1,2,3,2]) → true hasCycle([1]) → false hasCycle([5,5]) → true hasCycle([1,2,3,4,5]) → false hasCycle([1,2,3,4,3]) → true

ヒント

set を使って訪問済みの値を記録し、同じ値が 2 回目に出たら true を返す

チェック → 追加 の順番が大事。先に追加すると自分自身にヒットしてしまう

本物のリンクリストでは Floyd の Tortoise and Hare (slow / fast 2 ポインタ) を使うのが定番

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

関連レッスン

  • ソート済みリンクリストの merge

    ソート済みの 2 つの連結リストを 1 つにマージし、merge sort の核となる手法を理解する。

  • リンクリストの中央ノード取得

    slow / fast の 2 ポインタ法を使って連結リストの中央ノードの値を一発で取得する。

  • ソート済みリストの重複削除

    ソート済み連結リストから連続する重複ノードを除去し、in-place な編集の発想を身につける。

  • 第1章まとめクイズ

    連結リストの基本操作・サイクル検出・2 ポインタ法の理解度を確認するまとめクイズ。

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

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

  • リスト順序付きで複数の値を扱うデータ構造
  • ループ繰り返し処理。矢印で戻すか専用記号で示す
  • メモリプログラムとデータを一時保持する高速領域
  • 変数データに名前をつけて参照する仕組み
  • モジュール他ファイルから import できるPythonファイル
  • データ構造データを効率的に格納・操作するための方法。
  • 連結リスト各要素が次の要素へのポインタを持つ構造。
  • 配列サイズ固定の同型データの集まり
main.py
学習モード
エディタを読み込んでいます

メモ

リンクリストのサイクル検出

⌘S で保存