問題
連結リストのhead をnext を
- 各節は
val(値) とnext(次の節) を 持ちます。 Go の 節は ListNodeで、Val、Nextと大文字で 始まります - 例の
posは、輪の 作り方を 表す数です。 最後の 節の nextが、先頭から 数えて pos番 (0 から数える ) の 節へつながっています。 posが -1 なら輪はありません posは関数へは 渡りません。 関数が 受け取るのは headだけで、輪が あるか どうかは 節を たどって 自分で 見分けます - 節の
数は 0 以上 10000 以下、 値は どれも -100000 以上 100000 以下です。 違う 節が 同じ値を 持つこともあります
例では、pos で
入力と出力の例
例 1
最後の 9 の
入力
head = [4, 7, 1, 9]
pos = 1出力
true例 2
輪が
入力
head = [6, 2]
pos = -1出力
false例 3
節が 1 つで、
入力
head = [3]
pos = 0出力
true面接での聞かれ方
連結リストの
- 「連結リストに
輪が あるかを 判定してください」 - 見た
節を 集合に 覚える 書き方を 出すと、 ほぼ 必ず 「追加の メモリを O(1) に できますか?」と続きます - 書き終えた
あとに 「輪の 入り口の 節を 返せますか?」 「速い指は、 なぜ遅い指を 飛び越さずに 必ず 追いつくのですか?」と 聞かれる こともあります
ジュニアの
アルゴリズムのチートシートの「配列と文字列」に、この型の要点を表とコードでまとめています。
まず 考える手順
段 1
まずは
段 2
記憶をslow は 1 つずつ、fast は 2 つずつ
段 3
輪の
段 4
速い指をfast と fast.next の
解答
Python
Python
def has_cycle(head):
slow = head
fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow is fast:
return True
return FalseJavaScript
JavaScript
function hasCycle(head) {
let slow = head;
let fast = head;
while (fast !== null
&& fast.next !== null) {
slow = slow.next;
fast = fast.next.next;
if (slow === fast) {
return true;
}
}
return false;
}Go
Go
func hasCycle(
head *ListNode,
) bool {
slow, fast := head, head
for fast != nil &&
fast.Next != nil {
slow = slow.Next
fast = fast.Next.Next
if slow == fast {
return true
}
}
return false
}比べているのはis、===、==) です。
計算量
- 時間は O(n) です。
輪が なければ、 速い 指が 節の 数の 約半分の 回数で 終わりに 着きます。 輪が あれば、 遅い 指が 輪に 入るまでに n 回以内、 入ってから 重なるまでに 輪の 長さ以内の 回数で済みます - 使う
記憶は O(1) です。 指 2 本だけです - 段 1 の
集合の 書き方も 時間は O(n) ですが、 記憶は O(n) です
よく ある間違い
- 値を
集合に覚える。 [5, 5, 5]のように同じ値が 続くと、 輪が ないのに 「同じ値に 2 回来た」として 真を 返します。 覚えるのは 節そのものです fast.nextを確かめずに 2 つ進める。 節の 数が 奇数の リストで、 fast.nextが空のまま fast.next.nextを読み、 止まります。 条件は fastとfast.nextの両方です- 進める
前に比べる。 2 本とも headから始めるので、 進める 前に 比べると 最初の 1 回で 必ず重なり、 輪が なくても 真を 返します。 比べるのは 進めたあとです - 空の
リストを 見落とす。 headが空なのに head.nextを読むと 止まります。 繰り返しの 条件で fastを確かめて いれば、 最初に 偽で抜けます
解答を動かした版 Python 3.12.14Node.js 22.23.4Go 1.24.6確認日 2026年10月30日
面接での 話し方の例
書き始める
「通った
節を 集合に 覚えれば O(n) で 分かりますが、 記憶も O(n) 要ります。 遅い指を 1 つずつ、 速い指を 2 つずつ 進め、 輪が あれば 輪の 中で 差が 1 ずつ 縮んで 必ず重なり、 輪が なければ 速い 指が 先に 空に 着きます。 時間は O(n)、 記憶は O(1) です。」
書き終えたら、
「例 1 で
たどります。 1 回目は 遅い指が 7、 速い 指が 1 です。 2 回目は 遅い指が 1、 速い指は 9 から 7 へ 戻ります。 3 回目は 遅い指が 9、 速い 指も 1 から 9 へ 進み、 同じ節に 重なったので 真を 返します。」
