Çevrim bağlantılı listede çevrim başlatma düğümü bulmanın nasıl çalıştığını açıklayın?


162

Kaplumbağa ve Hare'nin toplantısının döngü varlığını tamamladığını anlıyorum, ancak kaplumbağayı tavşanı buluşma yerinde tutarken bağlantılı listenin başlangıcına taşımak, ardından her seferinde bir adım hareket ettirmek onları döngü başlangıç ​​noktasında buluşturuyor?


Başka bir açıklama: marcin-chwedczuk.github.io/…
csharpfolk

İnsanlar bu sorunun ilk iki cevabının ötesine bakmaya özen göstermediler. Üçüncü cevap oldukça iyi.
displayName

Yanıtlar:


80

Bu Floyd'un döngü algılama algoritması . Algoritmanın ikinci aşamasını soruyorsunuz - bir döngünün parçası olan bir düğüm bulduğunuzda, biri döngünün başlangıcını nasıl bulur ?

Floyd'un algoritmasının ilk bölümünde, tavşan kaplumbağanın her adımı için iki adım hareket ediyor. Kaplumbağa ve tavşan bir araya gelirse, bir döngü vardır ve buluşma noktası, döngünün bir parçasıdır, ancak mutlaka döngüdeki ilk düğüm değildir.

Kaplumbağa ve tavşan buluştuğunda, en küçük i (kaplumbağa tarafından atılan adım sayısı), X i = X 2i olacak şekilde bulduk . Mu, X 0'dan döngünün başlangıcına kadar atılacak adım sayısını temsil etsin ve lambda, döngünün uzunluğunu temsil etsin. Sonra i = mu + bir lambda ve 2i = mu + b lambda, burada a ve b, kaplumbağa ve tavşanın döngüden kaç kez geçtiğini gösteren tamsayılardır. Birinci denklemi ikinciden çıkarmak i = (ba) * lambda verir, bu yüzden i lambda'nın tamsayı katlarıdır. Bu nedenle, Xı + mu = Xmu . X i , kaplumbağa ve tavşanın buluşma noktasını temsil eder. Kaplumbağayı başlangıç ​​düğümüne geri taşırsanız X0 ve kaplumbağa ve tavşan aynı hızda devam etsin, mu ek adımlardan sonra kaplumbağa X mu'ya ulaşmış olacak ve tavşan X i + mu = X mu'ya ulaşmış olacak , böylece ikinci buluşma noktası döngü.


1
@Jim lewis Buluşma noktası elbette bir başlangıç ​​noktası olmayacak, ancak dediğim gibi, bu ikisinden birini bağlantılı listenin başlangıcına kaydırmak ve her ikisini aynı hızda hareket ettirmek onları döngünün başlangıç ​​noktasında buluşturur.
Tutkulu programcı

6
@Jim Lewis Döngü uzunluğunun katları olarak i'nin ilk buluşma noktası ile döngü başlangıcı arasındaki mesafe olarak nasıl sonuçlandığını açıklayabilirseniz harika olur.
Tutkulu programcı

7
@Passionate: Döngünün X_mubaşlangıcına (mu tanımına göre) ulaşmak için başlangıç ​​noktasından mu adımlar atın . Sonra i daha fazla adım atarsanız, burada i döngü uzunluğunun bir katıdır, sonunda döngü başlangıcında geri dönersiniz: X_mu + i= X_mu. Ancak ekleme değişmeli, bu yüzden başlangıçtan ilk buluşma noktasına ulaşmak için i adımlar atmaya eşdeğer X_i, sonra X_mudöngünün başlangıcına geri dönmek için ek adımlar atmaya eşdeğer .
Jim Lewis

2
@ankur: Buluşma noktası X_i ve döngü uzunluğunun bir katı olması gerektiğini (cevabımda üçüncü paragraf) gösterdik. Buluşma noktasından sonraki ek adımlardan sonra, şimdi X_ (i + mu) konumundasınız. Ancak, X'in bu özel özelliğinden dolayı X_ (i + mu) = X_ (mu + i) = X_mu olduğunu, bu nedenle buluşma noktasının ötesindeki adımların sizi döngünün başlangıcı olan X_mu'ya götürmesi gerektiğini gösterdik. Temel olarak modüler aritmetik, artı eklemenin değişmeli özelliği.
Jim Lewis

28
Kanıtınızda küçük bir sorun olduğunu düşünüyorum. Buluşma noktası idöngünün bir noktasında olduğu için, denklemin olması gerektiğini i = mu + k + a*lambdave döngü başlangıcından buluşma noktasına kadar adımın 2i = mu + k + b*lambdanerede kolduğunu düşünüyorum . Her iki denklemin çıkarılması da aynı sonucu verir.
Ivan Z. Siu

336

Http://en.wikipedia.org/wiki/Cycle_detection#Tortoise_and_hare adresinde sağlanan döngü algılama algoritmasını kendi kelimelerimle açıklığa kavuşturmaya çalışayım .

çizim

Nasıl çalışır

Yukarıdaki diyagramda olduğu gibi, bir döngü ile listenin başına işaret eden bir kaplumbağa ve bir tavşan (işaretçilerin adı) alalım.

Kaplumbağayı bir seferde 1 adım hareket ettirirsek ve her seferinde 2 adım tavşan yaparsak, sonunda bir noktada buluşacaklarını varsayalım. Öncelikle bu hipotezin doğru olduğunu gösterelim.

Şekilde, döngülü bir liste gösterilmektedir. Döngünün uzunluğu vardır nve başlangıçta mdöngüden birkaç adım ötedeyiz. Ayrıca, buluşma noktasının kdöngü başlangıcından birkaç adım uzakta olduğunu ve kaplumbağa itoplam adım attığında kaplumbağa ve tavşanın bir araya geldiğini varsayalım . (Hare 2io zamana kadar toplam adım atardı .).

Aşağıdaki 2 koşul geçerli olmalıdır:

1) i = m + p * n + k

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

Birincisi, kaplumbağanın ibasamakları hareket ettirdiğini ve bu iadımlarda önce döngüye girdiğini söylüyor . Daha sonra ppozitif bir sayı için döngü sürelerinden geçer p. Sonunda ktavşanla karşılaşana kadar daha fazla düğümün üzerinden geçer .

Benzer bir şey tavşan için de geçerlidir. 2iAdımları taşır ve bu 2iadımlarda önce döngüye girer. Daha sonra qpozitif bir sayı için döngü sürelerinden geçer q. Sonunda kkaplumbağa ile tanışana kadar daha fazla düğümün üzerinden geçer .

Tavşan iki kat daha fazla seyahat ederken kaplumbağa hızı ve buluşma noktasına ulaştıklarında zaman sabit kalır.

Yani basit hız, zaman ve mesafe ilişkisi kullanarak,

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 arasında ilk ikisi verilen listenin özellikleridir. Bu denklemi doğru yapan k, q, p için en az bir değer kümesi olduğunu gösterebilirsek hipotezin doğru olduğunu gösteririz.

Böyle bir çözüm kümesi aşağıdaki gibidir:

p = 0

q = m

k = m n - m

Bu değerlerin aşağıdaki gibi çalıştığını doğrulayabiliriz:

m + k = ( q - 2p ) n  

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

=> mn = mn.

Bu set için, iolduğu

i = m + p n + k

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

Tabii ki, bunun mutlaka mümkün olan en küçük şey olmadığını görmelisiniz. Başka bir deyişle, kaplumbağa ve tavşan daha önce birçok kez tanışmış olabilir. Ancak, bir noktada buluştuklarını en azından bir kez hipotezin doğru olduğunu söyleyebiliriz. Bu yüzden, birini bir adım diğerini 2 adım hareket ettirirsek buluşmaları gerekir.

Şimdi algoritmanın, döngünün başlangıcını nasıl bulacağımız ikinci kısmına gidebiliriz.

Döngü Başlangıcı

Kaplumbağa ve tavşan bir araya geldiğinde, kaplumbağayı listenin başına geri koyalım ve tavşanı tanıştıkları yerde tutalım (bu, döngü başlangıcından k adım uzakta).

Hipotez, aynı hızda hareket etmelerine izin verirsek (her ikisi için 1 adım), ilk kez tekrar buluştuklarında döngü başlangıcı olacaktır.

Bu hipotezi ispatlayalım.

İlk önce bazı kehanetlerin m'nin ne olduğunu söylediğini varsayalım.

Daha sonra, m + k adımlarını hareket ettirmelerine izin verirsek, kaplumbağa orijinal olarak tanıştıkları noktaya gelmelidir (k döngü başlangıcından uzaklaşır - şekle bakın).

Daha önce bunu göstermiştik m + k = (q - 2p) n.

M + k adımları n döngü uzunluğunun bir katı olduğundan, tavşan, bu arada, döngü (q-2p) sürelerinden geçer ve aynı noktaya geri döner (k döngü başlangıcından uzaklaşır).

Şimdi, m + k adımlarını hareket ettirmelerine izin vermek yerine, sadece m adımlarını hareket ettirmelerine izin verirsek, kaplumbağa döngü başlangıcına ulaşacaktır. Tavşan, (q-2p) rotasyonlarını tamamlamadan k adım kısa olur. Döngü başlangıcından önce k adımları başladığından, tavşan döngü başlangıcına varmak zorunda kalacaktı.

Sonuç olarak, bu, ilk kez bir dizi adımdan sonra başlayan döngüde buluşmaları gerektiğini açıklar (çünkü ilk kez kaplumbağa m adımlarından sonra döngüye yeni geldi ve zaten içinde olan tavşanı göremedi. devir).

Artık bildiğimiz kadar onları hareket ettirmemiz gereken adım sayısının listenin başlangıcından döngü başlangıcına kadar olan uzaklık olduğunu biliyoruz, m. Tabii ki, algoritma m'nin ne olduğunu bilmek zorunda değildir. Sadece kaplumbağaları ve tavşanları buluşana kadar her seferinde bir adım hareket ettirecektir. Buluşma noktası döngü başlangıcı olmalı ve adım sayısı döngü başlangıcına olan mesafe (m) olmalıdır. Listenin uzunluğunu bildiğimizi varsayarsak, m'yi liste uzunluğundan çıkarma döngüsünün uzunluğunu da hesaplayabiliriz.


1
Bu yüzden onlar doğru zaman buluşma başlangıç ​​noktası bu olduğunu düşünmüyorum aşağıdaki açıklamaya bakın: stackoverflow.com/a/19209858/1744146 <br> Lütfen yanılıyorsam bana bildirin
MrA

Açıklamanın ilk kısmı kusursuz. Ama ikinci kısımda bildiğim kadarıyla bir kusur var. "Bazı kehanetler m der" diyorsunuz, ancak m biliniyorsa, döngünün başlangıcına zaten sahipsiniz. Döngünün başlangıcının nerede olduğunu asla bilmediğinizde nasıl cevap alabilirim? Lütfen bana haber ver.
Gopichand

1
@Gopichand Son parayı tekrar okuyun ... sadece biraz m olduğunu varsayalım (eğer zaten bir döngü olduğunu kanıtladıysanız) .. ama m'nin değerini bilmiyorsunuz
Srinath

2
Şimdi bu gerçekten harika bir açıklama. Bu muhtemelen tüm internet üzerinde şu anda en iyi açıklamadır.
Arlene Batada

2
Denkleminiz m + k = (q - 2p) ndaha da basitleştirilebilir m + k = q*n. Bunun nedeni, kaplumbağanın kapladığı devir sayısının her zaman sıfır olacağıdır, çünkü tavşan kaplumbağa ile buluşmadan asla geçemez. Bunu düşün.
Arpit Jain

124

Bu resme bakın:

resim açıklamasını buraya girin

SlowPointer tarafından toplantıdan önce kat edilen mesafe = x + y

FastPointer tarafından toplantıdan önce kat edilen mesafe = (x + y + z) + y = x + 2y + z

FastPointer, slowPointer'ın iki katı hızda seyahat ettiğinden ve buluşma noktasına ulaşıldığında zaman sabittir .

Yani basit hız, zaman ve mesafe ilişkisi 2 (x + y) = x + 2y + z => x + 2y + z = 2x + 2y => x = z

Bu nedenle, slowPointer'ı bağlı listenin başlangıcına taşıyarak ve hem slowPointer hem de fastPointer'ı aynı anda bir düğümü hareket ettirerek, her ikisinin de kapsama mesafesi aynıdır .

Döngünün bağlı listede başladığı noktaya ulaşırlar.


10
Bu, slowPointer'ın döngüye girmeden önce fastPointer'ın döngüyü n kez gezdiği durumu dikkate almaz. Döngünün uzunluğunu belirtmek için l kullanın. FastPointer tarafından toplantıdan önce kat edilen mesafe = (x + y + z) + y = x + 2y + nl + z. Ve ortaya çıkan ilişki x = nl + z olacaktır.
Jingguo Yao

@JingguoYao: İşte bu durum
displayName

2
bu diyagram aşırı basittir. hızlı işaretçi yavaş işaretçiye ulaşmadan önce döngü boyunca birçok kez hareket edebilir.
Warren MacEvoy

70

Old Monk'un basit ve az oylanmış cevabı , hızlı koşucu sadece tek bir tam döngüyü tamamladığında döngüyü bulmayı açıklar. Bu cevapta, hızlı koşucu döngüyü yavaş koşucunun döngüye girmeden önce birkaç kez çalıştırdığı durumu açıklıyorum.


Aynı görüntüyü kullanarak:resim açıklamasını buraya girin

Hızlı koşucunun yavaş ve hızlı buluşmadan önce döngüyü m kez çalıştırdığını varsayalım . Bunun anlamı şudur ki:

  • Yavaş hareket mesafesi: x + y
  • Hızlı koşulan mesafe: x + m (y + z) + y yani buluştukları yerde ekstra y

Hızlı, yavaş hızın iki katı hızda çalıştığından ve aynı zamanda çalıştıklarından, yavaş koşulan mesafeyi iki katına çıkarırsak, mesafenin hızlı koştuğunu gösteririz. Böylece,

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

X için çözme,

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

Gerçek senaryoda bu, x = (m - 1) tam döngü çalışması + ekstra mesafe z anlamına gelir .

Bu nedenle, bir işaretçiyi listenin başına koyup diğerini toplantı noktasında bırakırsak, bunları aynı hızda hareket ettirmek, döngü içi işaretçinin döngünün m - 1 çalışmalarını tamamlayıp diğerini karşılamasıyla sonuçlanır. işaretçi sağa doğru döngü başlangıcında.


7
Hiç şüphe yok ki, yavaştan önce yavaş ve hızlı bir araya gelmenin nasıl bir döngüden fazla süreceği garanti edilir?
siraj

4
@siraj: Yavaş döngüde çalışmaz, hızlı yavaştan daha hızlı çalışır ve döngüye daha önce girer. Ve buluşacakları garantidir. Yavaş j + 1'de ve hızlı j'de ise, şimdi j + 2'de buluşacaklar. Yavaş j'de ve j + 1'de hızlı ise, j - 1'de zaten tanıştıkları anlamına gelir.
displayName

4
Yavaş döngü etrafında dönerse matematik hala çalışır: x + (y + z) m + y = 2 (x + (y + z) n + y), burada n, buluşmadan önce yavaşça döngü sayısıdır. Bu, (m-2n-1) (y + z) + z = x olarak çözülür. Bu, buluşma noktasından başlamak, (m-2n-1) kez gitmek demektir, buluşma noktasına geri döndünüz, sonra z'ye gidin, döngü başlangıcındasınız demektir. Bunu yapmak için, baş düğümden başlamak ve x düğümlerine gitmekle aynı şeydir.
mayas_mom

1
@mayas_mom: Matematik çalışıyor olabilir ama yavaş asla döngüden geçemez. Her zaman ya başlangıçta ya da ortasında bir yerde yakalanacaktır.
displayName

4
x = (m - 1) (y + z) + z döngü uzunluğu y + z olduğundan ve yalnızca konumla ilgili olduğundan bu genelleştirilebilir. Yani x = ((m - 1) (y + z))% (y + z)) + z Etkili olan x = z;
anshul garg

10

Çok çok basit. Göreceli hız açısından düşünebilirsiniz. Tavşan iki düğümü hareket ettirirse ve kaplumbağa bir düğümü hareket ettirirse, kaplumbağa tavşasına göre bir düğümü hareket ettirir (kaplumbağayı hareketsiz olarak kabul edin). Dolayısıyla, dairesel bağlantılı listede bir düğümü taşırsak, o noktada tekrar buluşacağımızdan eminiz.

Dairesel bağlantılı listenin içindeki bağlantılı noktayı bulduktan sonra, sorun iki bağlantılı liste sorununun kesişim noktasını bulmak için azaltılmıştır.


8

Şekil 1

İlk çarpışma sırasında, kaplumbağa yukarıda gösterildiği gibi m + k adımlarını hareket ettirdi . Tavşan kaplumbağadan iki kat daha hızlı hareket eder, yani tavşan 2 (m + k) adımda hareket eder. Bu basit gerçeklerden aşağıdaki grafiği elde edebiliriz.

Şekil 1

Bu noktada, kaplumbağayı başlangıca geri taşıyoruz ve hem tavşan hem de kaplumbağanın her seferinde bir adım hareket etmesi gerektiğini ilan ediyoruz. Tanım olarak, m adımdan sonra , kaplumbağa döngünün başlangıcında olacaktır. Tavşan nerede olacak?

Tavşan da döngünün başında olacak. Bu ikinci grafikten açıktır: kaplumbağa geri başına getirildiğinde zaman, tavşan oldu k son döngüsünün içine adımları. M adımdan sonra , tavşan başka bir döngüyü tamamlayacak ve kaplumbağa ile çarpışacaktır.


@WarrenMacEvoy Hiçbir noktada başlangıç ​​noktasında buluşmalarını önermedim. Şekiller açıkça belirtildiği gibi, döngünün başında tekrar buluşurlar .
skedastik

5

Yaklaşmak:

İki işaretçi vardır:

  • Bir kerede bir düğümü hareket ettiren yavaş bir işaretçi.
  • Bir seferde iki düğümü hareket ettiren hızlı bir işaretçi.

İki işaretçi buluşursa, bir döngü olduğunu kanıtlar. Bir kez tanıştıktan sonra, düğümlerden biri kafayı gösterecek ve her ikisinin de bir kerede bir düğüme gitmesini sağlayacaktır. Döngünün başında buluşacaklar.

Gerekçe: İki kişi dairesel bir pistte yürürken, biri diğerinin iki katı hızla, nerede buluşurlar? Tam olarak başladığı yer.

Şimdi, hızlı koşucunun kbir nadım turunda adım adım başlayacağını varsayın . nerede buluşacaklar? Tam olarak n-kadımlarla. Yavaş koşucu (n-k)basamakları içerdiğinde, hızlı koşucu k+2(n-k)basamakları kapsayacaktı . ( yani k+2n-2kadımlar, yani 2n-kadımlar ). yani (n-k)adımlar (Yol daireseldir ve buluştukları turların sayısı ile ilgilenmiyoruz; sadece buluştukları pozisyonla ilgileniyoruz).

Hızlı koşucu kilk etapta adımların başına nasıl başlamıştı ? Çünkü yavaş koşucuyu döngünün başlangıcına ulaşmak için birçok adım attı. Döngünün başlangıcı, baş düğümden k basamaktır.

Not: Her iki işaretçinin bir araya geldiği düğüm k, döngü başlangıcından (döngü içinde) ve baş düğümün de kdöngü başlangıcından birkaç adım uzaktadır. Dolayısıyla, bu düğümlerden 1 adım eşit hızda işaretçi ilerlediğimizde, döngü başlangıcında buluşacaklardır.

Bunun basit olduğuna inanıyorum. Herhangi bir parçanın belirsiz olup olmadığını lütfen bize bildirin.


4
Lütfen gelecekte yanıt verebilecek bir bağlantı yerine tam cevabı buraya
gönderin

4

Tamam, tavşan ve kaplumbağanın, döngünün başlangıcından k adım uzakta bir noktada buluştuğunu, döngü başlamadan önceki adım sayısının mu ve döngünün uzunluğunun L olduğunu varsayalım.

Şimdi buluşma noktasında ->

Kaplumbağa tarafından kapsanan mesafe = mu + a * L + k - Denklem 1

(Döngünün başlangıcına ulaşmak için atılan adımlar + döngünün 'a' yinelemelerini karşılamak için alınan adımlar + döngünün başlangıcından itibaren k adımları) (burada a bir miktar pozitif sabittir)

Tavşan tarafından kapsanan mesafe = mu + b * L + k - Denklem 2

(Döngünün başlangıcına ulaşmak için atılan adımlar + döngünün 'b' yinelemelerini karşılamak için alınan adımlar + döngünün başlangıcından itibaren k adımları) (burada b bir miktar pozitif sabittir ve b> = a)

Tavşan tarafından kapsanan ekstra mesafe = Denklem 2 - Denklem 1 = (ba) * L

Tavşan, kaplumbağadan 2 kat daha hızlı hareket ettiğinden, bu mesafenin kaplumbağanın başlangıç ​​noktasına olan mesafesine eşit olduğunu lütfen unutmayın. Bu, döngünün birden fazla geçişini dahil etmiyorsak, buluşma noktasının başlangıçtan uzaklığı olan 'mu + k' ile eşit olabilir.

Böylece, mu + k = (ba) * L

Bu nedenle, bu noktadan sonraki adımlar, döngünün başlangıcına geri dönecektir (döngünün başlangıcından itibaren k adımlar zaten buluşma noktasına ulaşmak için alınmış olduğundan). Bu, aynı döngüde veya sonraki döngülerin herhangi birinde gerçekleşebilir. Böylece, kaplumbağayı bağlantılı listenin başına götürürsek, döngünün başlangıç ​​noktasına ulaşmak için mu adımlar atar ve tavşan da döngünün başlangıcına ulaşmak için mu adımlar atar ve böylece ikisi de döngünün başlangıç ​​noktası.

PS Dürüst olmak gerekirse, aklımdaki orijinal posterle aynı soruya sahiptim ve ilk cevabı okudum, birkaç şeyi temizlediler, ancak nihai sonuca net bir şekilde ulaşamadım ve bu yüzden kendi yolumla yapmaya çalıştım ve anlamak daha kolay buldum.


genellikle döngünün başında
buluşmazlar

3

resim açıklamasını buraya girin görüntü kredisi

Çağrı mesafesi bir işaretçinin izlediği bağlantı sayısını ve algoritmanın yavaş işaretçiyi bir bağlantıyı ve hızlı işaretçiyi iki bağlantıyı hareket ettirdiği yineleme sayısını gösterir. Uzunluk C çevriminden önce, döngü ofseti k = 0 ila C-1 ile etiketlenmiş N düğümleri vardır.

Döngünün başlangıcına ulaşmak için yavaş, N zamanını ve mesafesini alır. Bu, hızlı bir şekilde döngüde N mesafesini alır (oraya gitmek için N, döndürmek için N). Yani N zamanında, yavaş çevrim çevrim k = 0'da ve hızlı çevrim ofset k = N mod C'de.

N mod C sıfırsa, şimdi yavaş ve hızlı eşleşir ve döngü N zamanında ve döngü konumu k = 0'da bulunur.

N mod C sıfır değilse, o zaman hızlı yavaş yavaş yakalamak zorundadır, ki bu sırada N, döngüde C- (N mod C) mesafesidir.

Hızlı, yavaşlamanın her 1'i için 2 hareket ettiğinden, her yinelemede mesafeyi 1 azalttığından, bu, N zamanında hızlı ve yavaş arasındaki mesafeyi, yani C- (N mod C) kadar ek zaman alır. Yavaş ofset 0'dan hareket ettiği için, bu aynı zamanda buluştukları ofsettir.

Bu nedenle, N mod C sıfırsa, faz 1, döngünün başlangıcındaki N yinelemelerinden sonra durur. Aksi takdirde, faz 1, C- (N mod C) ofsetinde döngü içine N + C- (N mod C) tekrarlarından sonra durur.

// 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;
}

Tamam, yani faz 2: yavaş, döngüye ulaşmak için N adımını alır, bu noktada hızlı (şimdi adım başına 1 hareket eder) (C- (N mod C) + N) mod C = 0'dadır. 2. aşamadan sonra döngünün başlangıcında.

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

Tamlık için, 3. aşama, döngü boyunca bir kez daha hareket ederek döngü uzunluğunu hesaplar:

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

Algoritmayı simüle etmek için Google Dokümanına bağlantı: docs.google.com/spreadsheets/d/…
Warren MacEvoy

1
N <= C ise, yinelemenin C yinelemelerinden sonra durduğunu unutmayın. Her durumda, N + C adımlarından daha az bir sürede durmalıdır ve döngünün başlangıcında durması olası değildir.
Warren MacEvoy

2

Sorunu bir döngü sorununa azaltın, sonra ilk soruna geri dönün

Aşağıdaki açıklamayı daha sezgisel buluyorum.

  1. (İki işaretçiler al 1 = kaplumbağa ve 2 kafası (başlamak = tavşan) O ), 1 arasındaki bir basamak uzunluğu 1 , 2 arasındaki bir basamak uzunluğunda 2 . 1'in o döngünün başlangıç ​​düğümüne ( A ) ulaştığı anı düşünün .

    Şu soruyu cevaplamak istiyoruz: "1, A'da 2 nerede?" .

    Yani, OA = adoğal bir sayıdır ( a >= 0). Ancak şu şekilde yazılabilir: a = k*n + bnerede a, k, n, b are natural numbers:

    • n = çevrim uzunluğu
    • k >= 0 = sabit
    • 0 <= b <= n-1

    Bu demektir b = a % n.

    Örneğin: if a = 20ve n = 8=> k = 2ve b = 4çünkü 20 = 2*8 + 4.

    Kat ettiği mesafe 1 olduğu d = OA = a = k*n + b. Ama aynı zamanda 2 kapak D = 2*d = d + d = OA + d = OA + k*n + b. Bu, 2 , A'da olduğunda kapsaması gerektiği anlamına gelir k*n + b. Gördüğünüz gibi, ktur sayısıdır, ancak bu turdan sonra, 2 olacak b nereye kadar A. So dan bulduğumuz 2 zaman olduğu 1 A. edelim çağrısı mesele olduğunu B, AB = b.

    resim açıklamasını buraya girin

  2. Şimdi, sorunu bir çembere indiriyoruz. Soru "Buluşma noktası nerede?" . Bu C nerede ?

    resim açıklamasını buraya girin

    Her adımda, 2 mesafeyi azaltır , 1 ile 1çünkü (diyelim diyelim metre) 1 dan olmaktadır 2 ile 1, ama aynı zamanda 2 yakın gider , 1 ile 2.

    Yani, kavşak 1 ile 2 arasındaki mesafe sıfır olduğunda olacaktır. Bu, 2n - b mesafeyi azalttığı anlamına gelir . Bunu başarmak için, 1 yapacak n - bolurken, adımlar 2 yapacaktır 2*(n - b)adımlar.

    Bu nedenle, kavşak noktası A'dan (saat yönünde) n - buzakta olacaktır , çünkü bu 1 ile 2 arasındaki mesafeyi kapsar . => Arasındaki mesafe C ve A olduğu , çünkü ve . Düşünmeyin çünkü mesafe önemsiz bir matematiksel mesafe değil, arasındaki adım sayısı olan A ve C ( A başlangıç noktasıdır ve C uç noktasıdır).CA = bAC = AB + BC = n - bCA = n - ACAC = CAAC

  3. Şimdi ilk şemaya geri dönelim.

    Bunu biliyoruz a = k*n + bve CA = b.

    2 '1' ve 1 '' işaretlerini alabiliriz , burada 1 ' kafadan başlar ( O ) ve 1' ' kesişme noktasından ( C ) başlar.

    İken 1' den gider O kadar A , '1' den geçer C için A ve bitiş devam ktur. Yani, kesişme noktasıdır A .

    resim açıklamasını buraya girin

    resim açıklamasını buraya girin


2

resim açıklamasını buraya girin

İşaretçiler şekilde gösterildiği gibi bir P noktasında buluşursa, Z + Y mesafesi P noktasıdır ve X + Y de P noktasıdır, yani Z = X anlamına gelir. Bu nedenle, bir işaretçiyi P'den hareket ettirmeye ve diğerini başlangıçtan (S) toplanana kadar hareket ettirmeye devam etmenin anlamı, eşit bir mesafeyi (Z veya X) aynı M noktasına (P'den Z'ye ve S'den S'ye mesafe) döngü başlangıcı. Basit!


1

Yukarıdaki tüm analizlerde, örnek bir öğrenen kişi iseniz, kısa bir analiz ve herkesin açıklamaya çalıştığı matematiği açıklamaya yardımcı olan bir örnek yazmaya çalıştım. İşte başlıyoruz!

Analiz:

Biri diğerinden daha hızlı olan ve birlikte hareket ettiren iki işaretçimiz varsa, sonunda bir döngüyü belirtmek için tekrar buluşacak veya hiçbir döngüyü belirtmek için null değerine sahip olacaklardır.

Döngünün başlangıç ​​noktasını bulmak için ...

  1. m başın döngünün başlangıcına kadar olan mesafe;

  2. d döngüdeki düğüm sayısı;

  3. p1 daha yavaş işaretçinin hızı olmalıdır;

  4. p2daha hızlı işaretçinin hızı, örn. 2, bir seferde iki düğümden geçen adımlar anlamına gelir.

    Aşağıdaki yinelemelere uyun:

 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

Yukarıdaki örnek verilerden, daha hızlı ve daha yavaş işaretçiler bir araya geldiğinde m, döngünün başlangıcından birkaç adım uzakta olduklarını kolayca keşfedebiliriz . Bunu çözmek için, daha hızlı işaretçiyi tekrar başınıza koyun ve hızını daha yavaş işaretçinin hızına ayarlayın. Tekrar buluştuklarında, düğüm döngünün başlangıcıdır.


1

diyelimki,

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

2 A ve B işaretçimiz var, A 1x hızda çalışıyor, B 2x hızda çalışıyor, her ikisi de başlangıçta başlıyor.

A N [0] 'a ulaştığında, B zaten N [m] cinsinden olmalıdır. (Not: A, N [0] değerine ulaşmak için m adımlarını kullanır ve B, m adımlarından fazla olmalıdır)

Daha sonra, A, B'ye çarpmak için daha fazla adım çalıştırır, yani A, N [k] 'de, B, N [m + 2k]' dir (Not: B, N [m] 'den başlayarak 2k adım için çalışmalıdır)

Sırasıyla N [k] ve N [m + 2k] 'de bir çarpışma B, k = m + 2k anlamına gelir, dolayısıyla k = -m

Böylece, N [k] 'dan N [0]' a geri dönmek için m adım daha gerekiyor.

Basitçe söylemek gerekirse, çarpışma düğümünü bulduktan sonra m adımlarını daha çalıştırmamız gerekiyor. Baştan itibaren bir işaretçi ve çarpışma düğümünden bir işaretçi olabilir, m adımlarından sonra N [0] 'da buluşacaklardır.

Bu nedenle, sözde kod aşağıdaki gibidir:

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

Bence buluştuklarında başlangıç ​​noktası budur. Ancak evet diğer işaretçi (F) daha önce buluşma noktasındaysa, bu işaretçi ilmeğin başlangıcı yerine döngünün sonunda ve listenin başından başlayan işaretçi (S) olacaktır. döngü başlangıcında sona erer. örneğin:

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

Lisede öğretilen göreceli hız fikrini kullanarak basit bir açıklama - Fizik 101 / Kinematik dersleri.

LinkedList'teki Çevre

  1. Bağlantılı listenin başlangıcından dairenin başlangıcına kadar olan mesafenin xatlama olduğunu varsayalım . Dairenin başlangıcını nokta olarak adlandıralım X(büyük harflerle - yukarıdaki şekle bakın). Ayrıca toplam çember boyutunun N atlama olduğunu varsayalım.

  2. Tavşan hızı = 2 * Kaplumbağa hızı. Yani bu 1 hops/secve 2 hops/secsırasıyla

  3. Kaplumbağa dairenin başlangıcına ulaştığında, Xtavşan ayrıca şekildeki xnoktada Yatlanmalıdır. (Çünkü tavşan kaplumbağa olarak iki kat mesafe kat etti).

  4. Böylece, kalan arkın X'ten Y'ye saat yönünde uzunluğu olacaktır N-x. T onun aynı zamanda onları karşılamak için muktedir için tavşan ve kaplumbağa arasında ele alınacak nispi mesafe olur . Diyelim ki bu nispi mesafe zamanla karşılanacak, t_myani buluşma zamanı. Bağıl hız (2 hops/sec - 1 hops/sec)yani 1 hops/sec. Böylece, göreli mesafe = göreceli hız X zamanı kullanarak, t= N-xsn alırız . Bu yüzden N-xhem kaplumbağa hem de tavşan için buluşma noktasına ulaşmak gerekecek .

  5. Şimdi N-xsaniyede ve 1 hops/sechızda, daha önce noktada bulunan kaplumbağa X, buluşma noktasına ulaşmak için Nx atlamalarını kapsayacaktır M. Bu yüzden, bir buluşma noktası bu aracı Molan N-xşerbetçiotu saat yönü tersinde Xolduğu => (daha fazla anlamına gelir) = xnoktadan kalan mesafe Miçin Xsaat yönünde.

  6. Ama xaynı zamanda Xbağlantılı listenin başlangıcından ulaşma noktasına olan mesafedir .

  7. Şimdi, hangi atlama sayısının xkarşılık geldiğini umursamıyoruz . LinkedList'in başına bir kaplumbağa ve buluşma noktasına bir kaplumbağa koyar Mve onların atlamasına / yürümesine izin Xverirsek, ihtiyaç duyduğumuz nokta (veya düğüm) olan noktada buluşacaklardır .


1

Bunu bir diyagramla çalışmak yardımcı olacaktır. Sorunu denklemler olmadan açıklamaya çalışıyorum.

  1. Tavşan ve kaplumbağanın bir daire içinde koşmasına ve tavşan iki kez kaplumbağa koşmasına izin verirsek, tavşan kaplumbağası için bir turun sonunda yarıya iner. Tavşan kaplumbağa iki tur sonunda 1 tur yapmış ve her ikisi de buluşuyor. Bu, tavşan üç kez koşuyorsa, tavşan 1 turu kaplumbağanın 1 / 3'üne eşit olduğu için tüm hız için geçerlidir, bu nedenle 3 tur sonunda tavşan kaplumbağası 1 turu kaplar ve buluşurlar.
  2. Şimdi onları döngüden önce m adımla başlatırsak, daha hızlı tavşan döngüde daha hızlı başlıyor demektir. Eğer kaplumbağa döngü başlangıcına ulaşırsa tavşan m adım önde döngüdür ve tanıştıklarında döngü başlamadan önce m adım olur.

1

- döngüden önce k adım vardır. K'nin ne olduğunu bilmiyoruz ve bulmamız gerekmiyor. Sadece k ile soyut çalışabiliriz.

- k adımdan sonra

----- T döngü başlangıcında

----- H, k döngüye girer (toplam 2k ve dolayısıyla k döngüye girer)

** şimdi loopsize - k apart

(k == K == mod (loopsize, k) --eg, bir düğüm 5 düğüm döngüsünde 2 adım ise, 7, 12 veya 392 adımdır, bu nedenle döngü wrt k ne kadar büyük değildir hesaba katmak.

Birbiri diğerinden iki kat daha hızlı hareket ettiği için birim zaman başına 1 adım hızında birbirlerini yakaladıkları için loopsize - k'de buluşacaklardır.

Bu, döngünün başlangıcına ulaşmak için düğümlerin alacağı ve böylece baştan başlayıp döngü başlangıcına ve çarpışma ile döngü başlangıcına olan mesafenin aynı olduğu anlamına gelir.

Şimdi ilk çarpışmadan sonra T'yi başa doğru hareket ettirin. Her biri 1 oranında hareket ederseniz, T ve H döngü başlangıcında toplanır. (her ikisi için k adımda)

Bu, algoritmanın:

  • kafadan çarpışana kadar T = t.next ve H.next.next hareketleri (T == H) (bir döngü var)

// döngünün uzunluğunu hesaplayarak, k = 0 veya T ve H'nin döngünün başında tanıştığı duruma dikkat edin

- T veya H'yi bir sayaçla hareket ettirerek döngünün uzunluğunu hesaplayın

- işaretçi T2'yi listenin başına götür

- döngü adımlarının işaretçi uzunluğunu taşıma

- başka bir işaretçi H2'yi başa götür

- T2 ve H2'yi döngü başlangıcında toplanana kadar birlikte hareket ettirin

bu kadar!


1

Buna zaten çok sayıda cevap var, ama bir keresinde bunun için daha görsel olarak sezgisel bir diyagram buldum. Belki diğer insanlara yardımcı olabilir.

Benim için ana aha anları:

  • Bölünmüş T içine (kaplumbağa) T1 (ön kıvrımlı) ve T2 (de-döngü). T = kaplumbağa, H = tavşan

  • Çıkarma T den H görsel olarak üst üste,. Geriye kalan ( H - T = H ' ) T'ye eşittir .

  • Kalan matematik oldukça basit. H'den, T'nin görsel olarak üst üste geldiği yerde çıkarın

-1

Bu sorun için zaten kabul edilmiş bir cevap olduğunu biliyorum ama yine de akıcı bir şekilde cevap vermeye çalışacağım. Varsayın:

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.

Şimdi, tavşan ve kaplumbağa, 't' başından sonra bir araya gelsin.

Gözlemler:

Kaplumbağa tarafından kat edilen mesafe = v * t = x + (bk) (diyelim)

Sonra, tavşan tarafından kat edilen mesafe = 2 * v * t = x + (b - k) + b (tavşan ilmekli kısmı zaten bir kez geçtiğinden)

Şimdi toplantı süreleri aynı.

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

=> x = k

Bu, elbette, ilmeklenmeyen yolun uzunluğunun, ilmek başlangıç ​​noktasının her ikisinin buluştuğu noktadan uzaklığı ile aynı olduğu anlamına gelir.


Kaplumbağaların buluştukları zaman tam olarak x + bk yol aldığını varsayamazsınız. Ayrıca, tavşanın uzaklığı için nasıl x + 2 * bk olduğunu anlamıyorum.
Plumenator

Çünkü tavşan kaplumbağayla tanışmak için bir kez ilmekledi kısmı geçecekti .. Ben orada açıklamamıştım: /
n0nChun

-1

Eğer buluşma noktasının arkasındaki matematiği düşünürseniz, her ikisinin de başlangıç ​​noktasında buluşacağını kanıtlamak gerçekten kolaydır.
İlk olarak m , bağlantılı listede döngünün başlangıç ​​noktasını, n ise döngünün uzunluğunu belirtir. Sonra tavşan ve kaplumbağa buluşması için:

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

Bunu daha matematiksel olarak belirtmek gerekirse:

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

böylece t zamanında toplanacaklar ki bu da çevrim uzunluğunun bir katı olmalıdır. Bu, bir yerde buluştukları anlamına gelir (t-m) modulo n = (0-m) modulo n = (-m) modulo n.

Şimdi soruya geri dönersek, bağlantılı listenin başlangıcından diğerini kavşak noktasından hareket ettirirseniz, m adımdan sonra tavşan (döngü içinde hareket eder) olan bir noktaya geleceğiz ((-m) + m) modulo n = 0 modulo nYani m adımından sonra döngünün başlangıcına gelir ve kaplumbağa orada buluşur , çünkü bağlantılı listenin başlangıcından itibaren m adımdan geçer.

Durum: Bir yan not olarak, biz de bu şekilde onların kavşağın zaman hesaplayabilirsiniz t = 0 modulo nonlar döngüsü uzunluğunun katı olduğu bir zamanda buluşacak söyler ve ayrıca t büyük olmalıdır m onlar bir araya geleceğini olarak devir . Böylece, geçen zaman n'nin m'den büyük olan ilk katına eşit olacaktır .


Döngünün başında buluşmaları gerekmez.
Warren MacEvoy

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.