速い指と 遅い指で 並びの 中の 重なった数を探す
1 から
海外で定番の問題リスト 4 本には入っていません
問題
整数のnums を
- 重なった
値は 2 回とは 限らず、 3 回以上出てくることもあります numsを書き換えてはいけません (並べ替えも、 印を 付けるのも 無しです) - 使う
記憶は O(1) に してください。 集合や数を 数える 表は 使えません - n は 1 以上 10000 以下です
入力と出力の例
例 1
座席の
例 2
重なった
例 3
いちばん
面接での聞かれ方
条件を
- 「重なった
数を 探してください」とだけ 聞かれ、 集合で 解くと 「記憶を O(1) に できますか?」 「並びを書き換えずに?」と 条件を 足されます - 並べ替える、
値の 位置に 負の 印を 付ける、という 答えは 「書き換えない」で 外されます - 値の
範囲で 二分探索する O(n log n) の 書き方を 答えると、 「O(n) に できますか?」と 続く ことがあります
ミドルの
ヒント
まだ開いていません
付箋は 4 枚。下の段ほど答えに近づきます
ヒント 2
ヒント 3
ヒント 4答えに近い
アルゴリズムのチートシートの「配列と文字列」に、
関わる学び
配列と
まず 考える手順
段 1
まずは
段 2
番号 i のnums[i] をnums[i] へ
段 3
連結リストの
段 4
出会ったら、
解答
Python
Python
def find_duplicate(nums):
slow = nums[0]
fast = nums[nums[0]]
while slow != fast:
slow = nums[slow]
fast = nums[nums[fast]]
slow = 0
while slow != fast:
slow = nums[slow]
fast = nums[fast]
return slowJavaScript
JavaScript
function findDuplicate(nums) {
let slow = nums[0];
let fast = nums[nums[0]];
while (slow !== fast) {
slow = nums[slow];
fast = nums[nums[fast]];
}
slow = 0;
while (slow !== fast) {
slow = nums[slow];
fast = nums[fast];
}
return slow;
}Go
Go
func findDuplicate(
nums []int,
) int {
slow := nums[0]
fast := nums[nums[0]]
for slow != fast {
slow = nums[slow]
fast = nums[nums[fast]]
}
slow = 0
for slow != fast {
slow = nums[slow]
fast = nums[fast]
}
return slow
}最初の
計算量
- 時間は O(n) です。
速い 指が 遅い指に 追いつくまでと、 入口まで もう 一度歩く 所が、 どちらも n の 数倍の 歩数で済みます - 使う
記憶は O(1) です。 指 2 本だけで、 並びは 読むだけです
よく ある間違い
- 出会った
所の 値を 答えにする。 出会う所は 輪の 中の どこかで、 入口とは 限りません。 nums = [2, 4, 3, 1, 3]では、遅い指と 速い指は 1 番で 出会いますが、 答えは 3 です。 2 段目の 歩きが要ります - 2 段目で、
もう 片方も 0 番に戻す。 戻すのは 片方だけです。 もう 片方は 出会った 所から 歩かせます - 番号と
値を 取り違える。 指が 持つのは 番号で、 次の 番号は nums[今の番号]です。最後に 返すのは、 入口の 番号 (それが 重なった 値) です - 並べ替えて
隣を比べる。 動きますが、 並びを 書き換えるので 条件に 合いません
解答を動かした版 Python 3.14.7Node.js 24.22.1Go 1.24.2確認日 2026年11月8日
面接での 話し方の例
書き始める
「番号 i から nums[i] へ
行く 矢印を 引くと、 連結リストに なります。 値は 1 から n なので 0 番には 戻らず、 n + 1 個から n 個へ 向けるので、 2 本の 矢印が 同じ 番号に 入る 所が あり、 そこが 輪の 入口で 重なった値です。 遅い指と 速い指で 輪の 中で 出会わせ、 片方を 0 番に 戻して 1 歩ず つ進めると 入口で 出会います。 時間は O(n)、 記憶は O(1) です。」
書き終えたら、
「例 1 では、
0 番から 3、 5、 2、 1、 4、 4、と 進み、 4 番からは 4 番へ 戻る 輪です。 遅い指と 速い指は 4 番で 出会います。 片方を 0 番に 戻して 1 歩ず つ進めると、 0 から 3、 5、 2、 1、 4 と、 出会った 側は 4 にとどまり、 4 で 出会うので 答えは 4 です。」