サイクルリンクリストでサイクル開始ノードを見つける方法について説明してください。


161

亀と野ウサギの会議はループの存在を終了することを理解していますが、ウサギを会議場所に置いたまま、リンクされたリストの先頭に亀を移動し、次に両方を1ステップずつ移動して、サイクルの開始点で会うにはどうすればよいですか?



人々は、この質問に対する最初の2つの答えを超えて見て気にしていない。3番目の答えはかなり良いです。
displayName

回答:


80

これは、サイクル検出用のフロイドのアルゴリズムです。アルゴリズムの第2フェーズについて質問しています。サイクルの一部であるノードを見つけたら、どのようにしてサイクルの開始を見つけるのでしょうか。

フロイドのアルゴリズムの最初の部分では、ウサギはカメのすべてのステップで2ステップ移動します。亀とうさぎが出会う場合は、循環があり、その集合点は循環の一部ですが、必ずしも循環の最初のノードではありません。

カメとウサギが出会ったとき、X i = X 2iとなるような最小のi(カメの歩数)を見つけました。muがX 0からサイクルの開始までのステップ数を表し、lambdaがサイクルの長さを表すとします。次に、i = mu + a ラムダ、2i = mu + bラムダです。ここで、aとbは、亀とウサギがサイクルを何回行ったかを表す整数です。2番目の方程式から最初の方程式を引くと、i =(ba)* lambdaとなるため、iはラムダの整数倍になります。 したがって、X i + mu = X muです。X iは、カメとウサギの出会いの場を表します。亀を最初のノードXに戻した場合0、そして亀とウサギが同じ速度で継続するようにします。mu追加のステップの後、亀はX muに到達し、ウサギはX i + mu = X muに到達します。したがって、2番目のミーティングポイントは、サイクル。


1
@ジム・ルイスもちろん、出会いのポイントは出発点ではありませんが、前述したように、2つのうちの1つをリンクリストの先頭に移動し、両方を同じ速度で移動すると、サイクルの出発点で出会います。
情熱的なプログラマー、

6
@Jim Lewisループの長さのiの倍数をiに設定すると、最初のミーティングポイントとループ開始点の間の距離としてmuがどのように得られるかについて説明できたらすばらしいと思います。
情熱的なプログラマー、

7
@Passionate:開始点からmuのステップを実行してX_mu、サイクルの開始(muの定義による)に到達します。次に、iをさらにステップ実行すると、iはサイクルの長さの倍数であり、最終的にサイクルの開始点に戻ります:X_mu + i= X_mu。しかし、加算は可換的であるため、これは、最初から最初のミーティングポイントに到達するためにiステップを実行しX_i、次にX_mu、サイクルの開始に戻るためにmu追加ステップを実行することと同じです。
ジム・ルイス

2
@ankur:ミーティングポイントはX_iであり、ループの長さの倍数である必要があることを(回答の3番目の段落)示しました。ミーティングポイントを超えてさらにmuの手順を実行すると、X_(i + mu)になります。ただし、iのこの特別なプロパティのため、X_(i + mu)= X_(mu + i)= X_muであることを示したので、muがミーティングポイントを通過すると、サイクルの開始点であるX_muに移動する必要があります。基本的にモジュラー演算、および加算の可換性。
ジム・ルイス

28
あなたの証明には小さな問題があると思います。待ち合わせポイントiはサイクルのある時点にあるので、方程式はi = mu + k + a*lambdaand 2i = mu + k + b*lambdaである必要があると思います。ここで、kはサイクルの開始から待ち合わせポイントまでのステップ数です。ただし、両方の方程式を引くと同じ結果になります。
Ivan Z. Siu

336

自分の言葉でhttp://en.wikipedia.org/wiki/Cycle_detection#Tortoise_and_hareで提供されているサイクル検出アルゴリズムを明確にしてみましょう。

お絵かき

使い方

上の図のように、リストの先頭をサイクルで指している亀とウサギ(ポインタの名前)を見てみましょう。

亀を一度に1歩ずつ動かし、一度に2歩歩くと、ある時点で最終的に出会うと仮定しましょう。まず、この仮説が真であることを示しましょう。

この図は、循環のあるリストを示しています。サイクルの長さはn、最初mはサイクルから離れています。また、出会いのポイントはk、サイクルの開始から少し離れたところにあり、亀がi完全な一歩を踏み出したときに亀とウサギが出会うとします。(ヘアはそれまでに2i完全なステップを踏んでいたでしょう。)

次の2つの条件が満たされている必要があります。

1) i = m + p * n + k

2) 2i = m + q * n + k

最初のものは、亀がiステップを動かし、これらのiステップで最初にサイクルに入ると言います。次に、p正の数のサイクルタイムを通過しますp。最後に、kウサギに出会うまで、より多くのノードを調べます。

ウサギについても同様です。2iステップを移動し、これらの2iステップで最初にサイクルに到達します。次に、q正の数のサイクルタイムを通過しますq。最後に、k亀に出会うまで、より多くのノードを通過します。

ウサギは亀の2倍の速度で移動するため、出会い地点に到達するまでの時間はどちらも一定です。

簡単な速度、時間、距離の関係を使用して、

2 ( m + p * n + k ) = m + q * n + k

=> 2m + 2pn + 2k = m + nq + k 

=>  m + k = ( q - 2p ) n

m、n、k、p、qのうち、最初の2つは指定されたリストのプロパティです。この方程式を真にするk、q、pの値のセットが少なくとも1つあることを示すことができれば、仮説が正しいことを示します。

そのようなソリューションセットの1つは次のとおりです。

p = 0

q = m

k = m n - m

これらの値が次のように機能することを確認できます。

m + k = ( q - 2p ) n  

=> m + mn - m = ( m - 2*0) n

=> mn = mn.

このセットのために、iあります

i = m + p n + k

=> m + 0 * n + mn - m = mn.

もちろん、これが必ずしも最小のiであるとは限らないことがわかります。つまり、亀とうさぎは何度も会ったことがあるかもしれません。しかし、少なくとも一度はそれらがどこかで出会うことを示しているので、仮説は正しいと言えます。したがって、それらの1つを1ステップずつ動かし、他の1つを2ステップずつ動かす場合、それらは一致する必要があります。

これで、アルゴリズムの2番目の部分であるサイクルの始まりを見つける方法に進むことができます。

サイクルの始まり

亀とうさぎが出会ったら、亀をリストの最初に戻し、出会った場所にうさぎを留めましょう(サイクルの開始からkステップ離れています)。

仮説は、彼らが同じ速度(両方とも1ステップ)で動くようにすると、彼らが再び会うのは初めてのときがサイクルの始まりになるということです。

この仮説を証明しましょう。

最初に、いくつかのオラクルがmが何であるかを教えてくれると仮定しましょう。

次に、m + kステップ移動させると、亀は最初に出会った地点に到着する必要があります(サイクルの開始からkステップ-図を参照)。

以前はそれを示しましたm + k = (q - 2p) n

m + kステップはサイクル長nの倍数であるため、うさぎは、平均すると、サイクル(q-2p)回を通過し、同じポイントに戻ります(サイクル開始からkステップ離れます)。

ここで、m + kステップだけ移動させるのではなく、mステップだけ移動させると、亀がサイクルの開始点に到達します。うさぎは(q-2p)回転を完了するのにkステップ足りません。サイクルの開始前にkステップ開始したため、ウサギはサイクルの開始に到達する必要があります。

その結果、これは、最初にいくつかのステップの後に始まるサイクルで初めて会う必要があることを説明します(亀はmステップ後にサイクルに到着したばかりで、すでに入っているウサギを見ることができなかったため、初めて)サイクル)。

これで、それらが出会うまでそれらを移動するために必要なステップの数は、リストの最初からサイクルの始まりmまでの距離であることがわかりました。もちろん、アルゴリズムはmが何であるかを知る必要はありません。カメを動かし、出会うまで一度に1歩ずつウサギを動かします。待ち合わせポイントはサイクルの開始点である必要があり、ステップ数はサイクルの開始点までの距離(m)でなければなりません。リストの長さがわかっていれば、リストの長さからmを引くサイクルの長さを計算することもできます。


1
:私は、彼らはそれが下の始点を参照してくださいコメントだ満たしたときに、その本当そうは思わないstackoverflow.com/a/19209858/1744146 <br> 私が間違っている場合は私に知らせてください
MRA

説明の最初の部分は完璧です。しかし、私が知る限り、第2部には欠陥があります。「いくつかのオラクルがmと言っている」と想定していますが、mがわかっている場合は、すでにサイクルの始まりです。サイクルの始まりがどこにあるかわからないときに、どうすれば答えを推測できますか?私にお知らせください。
Gopichand 2014

1
@Gopichand最後のパラグラフをもう一度読んでください... mがあると仮定します(すでにサイクルがあることが証明されている場合)。しかし、mの値がわかりません
Srinath

2
今、これは本当に素晴らしい説明です。これはおそらくインターネット全体で現在最も良い説明です。
Arlene Batada

2
方程式m + k = (q - 2p) nはさらにに簡略化できますm + k = q*n。これは、ウサギが亀に会わずに追い抜くことはできないため、亀が取るループの数は常にゼロになるためです。それについて考えてください。
Arpit Jain 2017

124

この画像を参照してください:

ここに画像の説明を入力してください

会議前にslowPointerが移動した距離 = x + y

会議前にfastPointerが移動した距離 =(x + y + z)+ y = x + 2y + z

fastPointerはslowPointerの2倍の速度で移動するため、がミーティングポイントに到達するまでの時間はどちらも一定です。

したがって、単純な速度、時間、距離の関係を使用して2(x + y)= x + 2y + z => x + 2y + z = 2x + 2y => x = z

したがって、slowPointerをリンクリストの先頭に移動し、slowPointerとfastPointerの両方が一度に1つのノードを移動するようにすると、どちらも同じ距離でをカバーできます。

それらは、リンクされたリストでループが開始するポイントに到達します。


10
これは、slowPointerがサイクルに入る前にfastPointerがサイクルをn回移動する場合を考慮していません。サイクルの長さを示すには、lを使用します。会議前にfastPointerが移動した距離 =(x + y + z)+ y = x + 2y + nl + z。そして、結果の関係はx = nl + zになります。
Jingguo Yao


2
この図は単純すぎます。高速ポインタは、低速ポインタが到達する前に、サイクルを何度も移動する可能性があります。
ウォーレンMacEvoy

70

Old Monkのシンプルで賛成されていない答えは、高速ランナーが単一の完全なサイクルのみを完了したときにサイクルを見つけることを説明しています。この回答では、遅いランナーがループに入る前に、速いランナーがループを複数回実行した場合について説明します。


同じ画像を使用:ここに画像の説明を入力してください

高速ランナーが低速と高速の出会いの前にループをm回実行したとします。この意味は:

  • スローが走る距離:x + y
  • 高速で走る距離:x + m(y + z)+ yつまり、それらが交わる余分なy

fastはslowの2倍の速度で実行され、同時に実行されているため、slowが実行した距離を2倍にすると、fastが実行した距離が得られます。したがって、

  • 2(x + y)= x + m(y + z)+ y

xを解くと、

x =(m-1)(y + z)+ z

実際のシナリオでは、x = (m-1)完全なループの実行+追加の距離zを意味します。

したがって、リストの最初に1つのポインターを置き、もう1つのポインターをミーティングポイントに置いたままにすると、それらを同じ速度で移動すると、ループ内ポインターがループのm-1回の実行を完了し、もう1つのループを満たします。ループの先頭にあるポインター。


7
1つの疑問..スローが1サイクル以上かかる前に、スローとファストが出会うことをどのように保証しますか?
siraj

4
@siraj:Slowはサイクルで実行されません。Slowは、Slowよりも速く実行され、以前にループに入るので、高速になります。そして、彼らが会うことは保証されています。遅いが、J + 1であると速いjのであれば、彼らは今、J + 2で会うと遅いが、J + 1で速いJであるとすれば、それは彼らがすでにJで会ったことを意味します- 1
のdisplayName

4
スローがループを回る場合でも数学は機能します:x +(y + z)m + y = 2(x +(y + z)n + y)。ここで、nは、スローがループする回数です。これは(m-2n-1)(y + z)+ z = xを解きます。つまり、ミーティングポイントから開始し、(m-2n-1)回移動すると、ミーティングポイントに戻り、次にzに移動します。ループの開始です。これを行うには、ヘッドノードから開始してxノードに移動するのと同じです。
mayas_mom

1
@mayas_mom:数学はうまくいくかもしれませんが、遅いのでループを回避できません。常に最初か途中のどこかで捕まります。
displayName

4
x =(m-1)(y + z)+ zこれは、ループの長さがy + zであり、位置のみを考慮しているため、一般化できます。したがって、x =((m-1)(y + z))%(y + z))+ zこれは事実上x = zです。
anshul garg 2017

10

とてもシンプルです。相対速度で考えることができます。ウサギが2つのノードを移動し、亀が1つのノードを移動する場合、亀は1つのノードを移動します(亀が静止していると仮定)。したがって、循環リンクリスト内の1つのノードを移動すると、そのポイントで再び会合することになります。

循環リンクリスト内の接続点を見つけた後、問題は2つのリンクリストの問題の交点を見つけることに還元されます。


8

図1

最初の衝突時に、亀は上記のようにm + kステップ移動しました。うさぎは亀の2倍の速度で移動します。つまり、うさぎは2(m + k)ステップ移動します。これらの単純な事実から、次のグラフを導き出すことができます。

図1

この時点で、亀を最初に戻し、ウサギと亀の両方が一度に1ステップずつ移動する必要があることを宣言します。定義により、mステップ後、亀はサイクルの開始点になります。野ウサギはどこにいますか?

うさぎもまた、サイクルの初めにいます。これは2番目のグラフから明らかです。亀が最初に戻ったとき、ウサギは最後のサイクルにk歩進みました。mステップ後、ウサギは別のサイクルを完了し、亀と衝突します。


@WarrenMacEvoyどの時点でも、彼らが開始点で会うことを提案しなかった。数字が明らかに示すように、彼らはサイクル初めに再び会います。
skedastik 2018

5

アプローチ:

2つのポインタがあります。

  • 一度に1つのノードを移動する低速ポインター。
  • 一度に2つのノードを移動する高速ポインター。

2つのポインターが出会った場合は、ループがあることを証明しています。それらが出会うと、ノードの1つがヘッドをポイントし、両方が一度に1つのノードを処理します。彼らはループの開始時に会います。

理論的根拠: 2人が円形のトラックを歩くとき、2人がもう1人の2倍の速度で歩いている場合、どこで出会いますか?まさに彼らが始まったところ。

ここで、ファストランナーがステップラップでkステップの先頭に立っているとしますn。彼らはどこで会いますか?まさにn-kステップで。スローランナーが(n-k)ステップをカバーした場合、ファーストランナーがk+2(n-k)ステップをカバーしたことになります。(すなわち、k+2n-2kステップすなわち2n-kステップ)。つまり、(n-k)ステップ数(パスは円形であり、それらが出会うまでのラウンド数は関係ありません。出会う位置だけに関心があります)。

さて、ファーストランナーはそもそもどのようにしkて最初のステップを開始したのでしょうか。ループの開始に到達するまでに多くのステップを実行するのに時間がかかるためです。したがって、ループの開始はヘッドノードからkステップです。

注:両方のポインターが出会ったノードはk、ループの開始(ループ内)kから少し離れており、ヘッドノードもループの開始から少し離れています。したがって、これらのノードをボットから1ステップの等速で前進するポインターがある場合、それらはループの開始時に出会います。

簡単だと思います。不明な部分がありましたらお知らせください。


4
将来リンクが壊れる可能性のあるリンクだけでなく、ここに完全な回答を投稿してください
Leeor

4

さて、サイクルの開始からkステップ離れたポイントでウサギとカメが出会うと仮定しましょう。サイクルが開始するまでのステップ数はmuで、サイクルの長さはLです。

だから今、待ち合わせ場所->

亀で覆われた距離= mu + a * L + k-式1

(サイクルの最初に到達するために取られるステップ+サイクルの「a」回の反復をカバーするために取られるステップ+サイクルの開始からkステップ)(ここで、aは正の定数です)

野ウサギがカバーする距離= mu + b * L + k-式2

(サイクルの最初に到達するために取られるステップ+サイクルの「b」回の反復をカバーするために取られるステップ+サイクルの開始からkステップ)(bはいくつかの正の定数であり、b> = a)

したがって、ウサギがカバーする追加の距離は=方程式2-方程式1 =(ba)* L

ノウサギはカメより2倍速く移動するため、この距離は開始点からのカメの距離にも等しいことに注意してください。これは 'mu + k'と同等である可能性があります。これは、サイクルの複数のトラバーサルを含めない場合の、最初からのミーティングポイントの距離でもあります。

したがって、mu + k =(ba)* L

したがって、このポイントからのmuステップは、サイクルの最初に戻ります(サイクルの開始からkステップは、ミーティングポイントに到達するためにすでに取得されているため)。これは、同じサイクルまたは後続のサイクルのいずれかで発生する可能性があります。したがって、リンク先のリストの先頭に亀を移動すると、サイクルの開始点に到達するまでにmuのステップが必要になり、ウサギがサイクルの開始点に到達するまでにmuのステップが実行されます。サイクルの開始点。

PS正直なところ、私は元のポスターと同じ質問を心に抱き、最初の回答を読みました。彼らはいくつかのことをクリアしましたが、最終結果を明確に得ることができなかったので、私は自分の方法でそれを試みました理解しやすかった。


彼らは通常、サイクルの最初に会わない
ウォーレンMacEvoy

3

ここに画像の説明を入力してください 画像クレジット

ポインターがたどるリンクの数と、低速ポインターを1つのリンクに、高速ポインターを2つのリンクに移動するためにアルゴリズムが実行する反復回数に時間をかけます。長さCのサイクルの前にN個のノードがあり、サイクルオフセットk = 0からC-1までのラベルが付けられています。

サイクルの開始に到達するには、スローにはN時間と距離がかかります。これは、サイクルでNの距離が高速にかかることを意味します(Nはそこに到達し、Nはスピンします)。したがって、時間Nでは、低速はサイクルオフセットk = 0にあり、高速はサイクルオフセットk = N mod Cにあります。

N mod Cがゼロの場合、低速と高速が一致し、サイクルは時間Nでサイクル位置k = 0で検出されます。

N mod Cがゼロでない場合、fastはslowに追いつく必要があります。このとき、NはサイクルのC-(N mod C)の距離の遅れです。

fastは、slowの1ごとに2を移動し、反復ごとに距離を1ずつ減らすため、これには、Nでのfastとslowの間の距離(C-(N mod C))と同じだけ多くの時間がかかります。slowはオフセット0から移動しているため、これらが出会うオフセットでもあります。

そのため、N mod Cがゼロの場合、フェーズ1はサイクルの開始時にN回の反復後に停止します。それ以外の場合、フェーズ1は、サイクルへのオフセットC-(N mod C)でのN + C-(N mod C)の反復後に停止します。

// C++ pseudocode, end() is one after last element.

int t = 0;
T *fast = begin();
T *slow = begin();
if (fast == end()) return [N=0,C=0];
for (;;) {
    t += 1;
    fast = next(fast);
    if (fast == end()) return [N=(2*t-1),C=0];
    fast = next(fast);
    if (fast == end()) return [N=(2*t),C=0];
    slow = next(slow);
    if (*fast == *slow) break;
}

わかりましたので、フェーズ2:スローはサイクルに到達するまでにさらにNステップを要します。この時点で、ファスト(タイムステップごとに1つ移動)は(C-(N mod C)+ N)mod C = 0になります。フェーズ2の後のサイクルの開始時。

int N = 0;
slow = begin();
for (;;) {
    if (*fast == *slow) break;
    fast = next(fast);
    slow = next(slow);
    N += 1;
}

完全を期すために、フェーズ3はサイクルをもう一度移動することによってサイクルの長さを計算します。

int C = 0;
for (;;) {
    fast = next(fast);
    C += 1;
    if (fast == slow) break;
}

リンクシミュレートするアルゴリズムにドキュメントをGoogleに:docs.google.com/spreadsheets/d/...
ウォーレンMacEvoy

1
N <= Cの場合、C回の反復後に反復が停止することに注意してください。いずれの場合も、N + Cステップ未満で停止する必要があり、サイクルの開始時に停止することはほとんどありません。
Warren MacEvoy

2

問題をループ問題に減らしてから、最初の問題に戻ります

次の説明の方が直感的です。

  1. (二つのポインタを取る1 =亀と2頭(から始まる=ウサギ)Oが)、1のステップ長持つ12のステップ長持つ21がそのサイクルの開始ノード(A)に到達した瞬間を考えてみてください。

    次の質問に答えたいと思います。

    つまり、OA = aは自然数(a >= 0)です。しかし、それは次のように書くことができます:a = k*n + bここでa, k, n, b are natural numbers

    • n =サイクルの長さ
    • k >= 0 =一定
    • 0 <= b <= n-1

    ということb = a % nです。

    例:if a = 20およびn = 8=> k = 2およびb = 4because 20 = 2*8 + 4

    1でカバーされる距離はd = OA = a = k*n + bです。しかし同時に、2がカバーしD = 2*d = d + d = OA + d = OA + k*n + bます。これは、2がAの場合、カバーする必要があることを意味しますk*n + b。あなたが見ることができるように、kラップの数があるが、これらのラップの後、2になりますbはどこ遠くA.そうから、我々が発見2がときである1が A.レッツ・コール、その点でありBAB = b

    ここに画像の説明を入力してください

  2. 今、私たちは問題を円に減らします。問題は、「待ち合わせ場所はどこですか」です。。そのCはどこですか

    ここに画像の説明を入力してください

    すべてのステップでは、2からの距離が減少し11あるため(LETの言うメーター)1からさらになっている21が、同時に2が近づくに行く1によります2

    したがって、交差は12の間の距離がゼロになるときになります。つまり、2n - b距離を短くします。これを達成するために、1n - bステップを実行し、22*(n - b)ステップを実行します。

    したがって、交点n - bA(時計回り)から遠くなります。これは、2に出会うまで1でカバーされる距離だからです。=>との間の距離CAがであり、なぜなら、および。それを考えてはいけないので、距離は些細な数学的な距離ではありません、それは間のステップ数で、ACAは、開始点であるとCは、エンドポイントです)。CA = bAC = AB + BC = n - bCA = n - ACAC = CAAC

  3. では、最初のスキーマに戻りましょう。

    我々はそれを知っているa = k*n + bCA = b

    私たちは、2つの新しいポインタ取ることができます1'及び1 『』を、どこ1'頭(から始まりO)および1 『』交点(から始まるC)。

    一方で1'から行くOA『1』から行くCAとフィニッシュまで続くkラップ。したがって、交点はAです。

    ここに画像の説明を入力してください

    ここに画像の説明を入力してください


2

ここに画像の説明を入力してください

図に示すようにポインタが点Pで出会った場合、距離Z + Yは点Pであり、X + Yも点Pであり、これはZ = Xを意味します。これが、あるポインタをPから移動し、別のポインタをstart(S)からそれらが出会うまで移動し続ける理由です。つまり、等しい距離(ZまたはX)を同じ点M(Pからの距離ZおよびSからの距離)に移動すると、ループの開始。シンプル!


1

上記のすべての分析で、例で学習する人であれば、他の誰もが説明しようとした数学を説明するのに役立つ短い分析と例を書いてみました。さあ行こう!

分析:

2つのポインターがあり、一方が他方よりも速く、一緒に移動する場合、それらは最終的に再び会合してサイクルを示すか、nullでサイクルがないことを示します。

サイクルの開始点を見つけるには、...

  1. m 頭からサイクルの開始までの距離。

  2. d サイクル内のノード数。

  3. p1 遅いポインタの速度です。

  4. p2より速いポインタの速度である、例えば。2は、一度に2つのノードをステップ実行することを意味します。

    次の反復を観察します。

 m = 0, d = 10:
 p1 = 1:  0  1  2  3  4  5  6  7  8  9 10 // 0 would the start of the cycle
 p2 = 2:  0  2  4  6  8 10 12 14 16 18 20

 m = 1, d = 10:
 p1 = 1: -1  0  1  2  3  4  5  6  7  8  9
 p2 = 2: -1  1  3  5  7  9 11 13 15 17 19

 m = 2, d = 10:
 p1 = 1: -2 -1  0  1  2  3  4  5  6  7  8
 p2 = 2: -2  0  2  4  6  8 10 12 14 16 18

上記のサンプルデータから、速いポインターと遅いポインターが出会うときはいつでも、それらはmサイクルの開始から一歩離れていることが簡単にわかります。これを解決するには、速いポインターを先頭に戻し、その速度を遅いポインターの速度に設定します。彼らが再び会うとき、ノードはサイクルの始まりです。


1

まあ言ってみれば、

N[0] is the node of start of the loop, 
m is the number of steps from beginning to N[0].

2つのポインターAとBがあります。Aは1倍速で実行され、Bは2倍速で実行されます。どちらも最初から開始されます。

AがN [0]に達したとき、BはすでにN [m]にあるはずです。(注:AはN [0]に到達するためにmステップを使用し、Bはさらにmステップでなければなりません)

次に、Aはさらにkステップ実行してBに衝突します。つまり、AはN [k]にあり、BはN [m + 2k]にあります(注:BはN [m]から2kステップ実行する必要があります)

AはそれぞれN [k]とN [m + 2k]で衝突します。これはk = m + 2kを意味するため、k = -m

したがって、N [k]からN [0]にサイクルバックするには、さらにmステップが必要です。

簡単に言うと、衝突ノードが見つかった後、さらにmステップ実行する必要があります。最初から実行するポインタと衝突ノードから実行するポインタを設定できます。これらは、mステップ後にN [0]で交わります。

したがって、擬似コードは次のとおりです。

1) A increase 1 step per loop
2) B increase 2 steps per loop
3) if A & B are the same node, cycle found, then go to 5
4) repeat from 1
5) A reset to head
6) A increase 1 step per loop
7) B increase 1 step per loop
8) if A & B are the same node, start of the cycle found
9) repeat from 6

1

彼らが出会ったときにそれが出発点であるというのは本当ではないと思います。しかし、他のポインター(F)がの前のミーティングポイントにあった場合、そのポインターはループの開始ではなく、ループの最後にあり、リストの開始から開始したポインター(S)は、ループの開始時に終了します。たとえば:

1->2->3->4->5->6->7->8->9->10->11->12->13->14->15->16->17->18->19->20->21->22->23->24->8

Meet at :16

Start at :8

public Node meetNodeInLoop(){

    Node fast=head;
    Node slow=head;

    fast=fast.next.next;
    slow=slow.next;

    while(fast!=slow){

        fast=fast.next;
        fast=fast.next;

        if(fast==slow) break; 

        slow=slow.next;
    }

    return fast;

}

public Node startOfLoop(Node meet){

    Node slow=head;
    Node fast=meet;

    while(slow!=fast){
        fast=fast.next;
        if(slow==fast.next) break;
        slow=slow.next;
    }

    return slow;
}

1

高校で教えられた相対速度の概念を使用した簡単な説明-物理学101 /運動学の講義。

LinkedListのサークル

  1. リンクされたリストの開始からサークルの開始までの距離がxホップであると仮定しましょう。円の始点をポイントと呼びましょうX(大文字で-上図を参照)。また、円の合計サイズがNホップであると仮定します。

  2. ノウサギの速度= 2 *カメの速度。つまり1 hops/sec2 hops/secそれぞれ

  3. 亀が円の始点に到達するXと、ノウサギは図のxポイントYでさらにホップを離れる必要があります。(ウサギが亀の2倍の距離を移動したため)。

  4. したがって、XからYへの時計回りの残りの弧の長さはになりますN-x。これは、うさぎとカメが出会うために必要な相対距離でもあります。この相対距離がt_m時間内に満たされる、つまり、会う時間になるとしましょう。相対速度がある(2 hops/sec - 1 hops/sec)すなわち1 hops/sec。したがって、相対距離=相対速度X時間を使用すると、t= N-x秒になります。したがってN-x、カメとウサギの両方の待ち合わせ場所に到達するまでに時間がかかります。

  5. 今ではN-x秒の時間とで1 hops/secスピード、早い時点でいた亀XのNxをカバーするには、ミーティングポイントに到達するためにホップM。つまり、ミーティングポイントMは、(さらに意味する)=> N-xから反時計回りのホップにXありx、ポイントMからX時計回りまでの距離が残っていることを意味します。

  6. しかし、リンクされたリストの最初からx到達点Xまでの距離でもあります。

  7. ここで、ホップ数が何であるかは関係ありませんx。LinkedListの先頭に1匹のカメを置き、ミーティングポイントに1匹のカメを置いMてホップ/ウォークさせるXと、必要なポイント(またはノード)であるポイントで合体します。


1

これを図で操作すると役立ちます。方程式なしで問題を説明しようとしています。

  1. うさぎとかめを輪にして、うさぎがかめを2度走らせると、1ラップの終わりにうさぎが亀の半分になります。ウサギのカメからの2ラップの終わりに1ラップを実行し、両方が出会うことになります。これは、うさぎが3回走る場合のようなすべての速度に適用されます。うさぎ1ラップは亀の3分の1に等しいので、うさぎの3ラップの終わりには1ラップをカバーし、それらは出会います。
  2. ループをmステップ前に開始すると、ループ内でより早いウサギが先に開始されることになります。したがって、亀がループの開始点に到達した場合、ノウサギはmステップ先のループであり、それらが出会うと、ループ開始前のmステップ分になります。

1

-ループの前にkステップあります。私たちはkが何であるかを知りませんし、知る必要もありません。kだけで抽象的に作業できます。

-kステップ後

----- Tはサイクル開始時

----- Hはサイクルへのkステップです(彼は合計で2kになり、したがってループにk入りました)

**それらはループサイズになりました-k離れています

(k == K == mod(loopsize、k)であることに注意してください。たとえば、ノードが5ノードサイクルに2ステップある場合、7、12、または392ステップもあるので、サイクルの大きさはkではありません。要因で。

一方が他方の2倍の速度で移動しているため、単位時間あたり1ステップの速度で互いに追いつくため、loopsize-kで出会います。

これは、サイクルの開始点に到達するためにk個のノードを必要とすることを意味し、したがって、ヘッドからサイクルスタートまでの距離と衝突からサイクルスタートまでの距離は同じです。

したがって、最初の衝突の後、Tを頭に戻します。TとHは、それぞれ1のレートで移動する場合、サイクルスタートで出会います。(両方でkステップ)

つまり、アルゴリズムは次のとおりです。

  • 頭からT = t.nextとH.next.nextが動くまで(T == H)(サイクルがある)

//ループの長さを計算して、k = 0、またはTとHがループの先頭で出会った場合に対応

-カウンターでTまたはHを移動してサイクルの長さをカウントします。

-ポインタT2をリストの先頭に移動します

-サイクルステップのポインタ長を移動します。

-別のポインタH2を先頭に移動します。

-サイクルの開始時に出会うまで、T2とH2をタンデムに移動します

それでおしまい!


1

これに対する答えはすでにたくさんありますが、私はかつてこの図を思い付きました。多分それは他の人々を助けることができます。

私にとっての主なアハモーメントは次のとおりです。

  • スプリットTに(カメ)T1(プレループ)とT2(インループ)。 T =亀、H =ウサギ

  • HからTを引きます。これらは視覚的に重なっています。残っているもの(H-T = H ')はTに等しい。

  • 残りの数学は非常に簡単です。 Hから、Tが視覚的に重なる場所を差し引く

-1

この問題についてはすでに認められた回答があることは知っていますが、それでも流動的な方法で回答するように努めます。想定:

The length of the Path is 'X+B' where 'B' is the length of the looped path and X of the non looped path. 
    Speed of tortoise : v
    Speed of hare     : 2*v 
    Point where both meet is at a distance 'x + b - k' from the starting point.

さて、ウサギとカメは最初から「t」後に会いましょう。

観察:

もし、カメが移動した距離= v * t = x +(bk)(たとえば)

次に、うさぎが移動した距離= 2 * v * t = x +(b-k)+ b(うさぎがループした部分をすでに通過したため)

現在、会議の時間は同じです。

=> x + 2 * b-k = 2 *(x + b-k)

=> x = k

もちろん、これは、ループされていないパスの長さが、両方が交わるポイントからループの開始ポイントまでの距離と同じであることを意味します。


亀が出会うまでにx + bkを正確に移動したとは限りません。また、うさぎの距離でx + 2 * bkがどのように得られたかはわかりません。
Plumenator 2012

ウサギが満たさ亀に持って一度すでに、ループ状部分を横断していたので..私はそこにそれを説明していませんでした:/
n0nChun

-1

出会い系の背後にある数学を考えると、両方が開始点で出会うことを証明するのは実際には簡単です。
まず、mはリンクリストのサイクルの開始点を示し、nはサイクルの長さを示します。次に、ノウサギとカメに会うために、

( 2*t - m )%n = (t - m) %n, where t = time (at t = 0 , both are at the start)

これをより数学的に述べる:

(2*t - m - (t - m) ) = 0 modulo n , which implies , t = 0 modulo n 

そのため、それらはサイクルtの倍数であるはずの時間tで出会います。これは、彼らがである場所で会うことを意味し (t-m) modulo n = (0-m) modulo n = (-m) modulo nます。

したがって、質問に戻って、リンクリストの先頭から1つのポインタを移動し、交点から別のポインタを移動すると、mステップ後に、ウサギ(サイクル内で移動している)が((-m) + m) modulo n = 0 modulo nこれは、サイクルの開始点にすぎません 。リンクされたリストの先頭からmステップ移動するので、mステップ後にサイクルの開始となり、亀がそこでそれに出会うことがわかります。

条件は:サイドノートとして、我々はまた、このように自分の交差点の時間を計算することができt = 0 modulo n、彼らはサイクル長の倍数である時に会うことを教えてくれるし、またtはより大きくなければなりませメートル彼らが会うようサイクル。したがって、かかる時間は、mより大きいnの最初の倍数に等しくなります。


彼らは必ずしもサイクルの開始時に会う必要はありません。
Warren MacEvoy

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.