Giải thích cách tìm nút bắt đầu chu kỳ trong danh sách liên kết chu kỳ hoạt động?


161

Tôi hiểu rằng cuộc họp của Rùa và thỏ kết luận sự tồn tại của vòng lặp, nhưng làm thế nào để rùa di chuyển đến đầu danh sách được liên kết trong khi giữ thỏ rừng ở nơi gặp gỡ, tiếp theo là di chuyển cả hai bước tại một thời điểm khiến chúng gặp nhau tại điểm bắt đầu của chu kỳ?


Một lời giải thích khác: marcin-chwedczuk.github.io/ từ
csharpfolk

Mọi người đã không quan tâm để nhìn xa hơn hai câu trả lời đầu tiên cho câu hỏi này. Câu trả lời thứ ba là khá tốt.
displayName

Câu trả lời:


80

Đây là thuật toán của Floyd để phát hiện chu kỳ . Bạn đang hỏi về giai đoạn thứ hai của thuật toán - một khi bạn đã tìm thấy một nút là một phần của chu kỳ, làm thế nào để tìm thấy điểm bắt đầu của chu kỳ?

Trong phần đầu tiên của thuật toán Floyd, thỏ rừng di chuyển hai bước cho mỗi bước của rùa. Nếu rùa và thỏ từng gặp nhau, có một chu kỳ và điểm gặp gỡ là một phần của chu kỳ, nhưng không nhất thiết là nút đầu tiên trong chu kỳ.

Khi rùa và thỏ gặp nhau, chúng tôi đã tìm thấy i nhỏ nhất (số bước được thực hiện bởi rùa) sao cho X i = X 2i . Đặt mu đại diện cho số bước để đi từ X 0 đến đầu chu kỳ và để lambda biểu thị độ dài của chu kỳ. Sau đó i = mu + a lambda và 2i = mu + b lambda, trong đó a và b là các số nguyên biểu thị số lần rùa và thỏ đi vòng quanh chu kỳ. Trừ phương trình thứ nhất từ ​​phương trình thứ hai cho i = (ba) * lambda, vì vậy tôi là bội số nguyên của lambda. Do đó, X i + mu = X mu . X i đại diện cho điểm gặp gỡ của rùa và thỏ. Nếu bạn di chuyển rùa trở lại nút bắt đầu X0 , và để rùa và thỏ tiếp tục ở cùng một tốc độ, sau khi các bước bổ sung của mu, rùa sẽ đến X mu , và thỏ sẽ đạt X i + mu = X mu , vì vậy điểm gặp gỡ thứ hai biểu thị sự bắt đầu của đi xe đạp.


1
@Jim lewis Điểm gặp gỡ tất nhiên sẽ không phải là điểm khởi đầu, nhưng như tôi đã nói, việc chuyển một trong hai thứ đó sang đầu danh sách được liên kết và di chuyển cả hai cùng tốc độ sẽ khiến chúng gặp nhau tại điểm bắt đầu của chu kỳ.
Lập trình viên đam mê

6
@Jim Lewis Sẽ thật tuyệt nếu bạn có thể giải thích về việc làm thế nào tôi có nhiều kết quả chiều dài vòng lặp đến mu như khoảng cách giữa điểm gặp gỡ đầu tiên và bắt đầu vòng lặp.
Lập trình viên đam mê

7
@Passionate: Thực hiện các bước mu từ điểm bắt đầu để đến X_mu, bắt đầu chu kỳ (theo định nghĩa của mu). Sau đó, nếu bạn thực hiện thêm i bước nữa, trong đó tôi là bội số của độ dài chu kỳ, bạn sẽ trở lại vào lúc bắt đầu chu kỳ: X_mu + i= X_mu. Nhưng bổ sung là giao hoán, vì vậy điều này tương đương với việc tôi thực hiện các bước để bắt đầu từ điểm bắt đầu đến điểm gặp đầu tiên X_i, sau đó là các bước bổ sung để quay lại X_mu, bắt đầu chu kỳ.
Jim Lewis

2
@ankur: Điểm gặp gỡ là X_i và chúng tôi đã chỉ ra (đoạn thứ ba trong câu trả lời của tôi) rằng tôi phải là bội số của độ dài vòng lặp. Sau khi mu bước bổ sung qua điểm gặp gỡ, bây giờ bạn đang ở X_ (i + mu). Nhưng chúng tôi đã chỉ ra rằng X_ (i + mu) = X_ (mu + i) = X_mu, vì thuộc tính đặc biệt này của i, vì vậy mu bước qua điểm gặp gỡ phải đưa bạn đến X_mu, bắt đầu chu kỳ. Về cơ bản số học mô-đun, cộng với tính chất giao hoán của phép cộng.
Jim Lewis

28
Tôi nghĩ rằng có một vấn đề nhỏ trong bằng chứng của bạn. Vì điểm gặp gỡ ilà tại một số điểm của chu kỳ, tôi nghĩ rằng phương trình nên i = mu + k + a*lambda2i = mu + k + b*lambda, ksố bước từ chu kỳ bắt đầu đến điểm gặp gỡ là ở đâu. Trừ cả hai phương trình cho kết quả như nhau mặc dù.
Ivan Z. Siu

336

Hãy để tôi thử làm rõ thuật toán phát hiện chu kỳ được cung cấp tại http://en.wikipedia.org/wiki/Cycl_detection#Tortoir_and_hare bằng từ ngữ của riêng tôi.

đang vẽ

Làm thế nào nó hoạt động

Chúng ta hãy có một con rùa và thỏ rừng (tên của con trỏ) chỉ vào đầu danh sách với một chu kỳ, như trong sơ đồ trên.

Chúng ta hãy đưa ra giả thuyết rằng nếu chúng ta di chuyển rùa 1 bước một lần và tăng 2 bước một lần, cuối cùng chúng sẽ gặp nhau tại một điểm. Chúng ta hãy chứng minh rằng trước hết giả thuyết này là đúng.

Hình minh họa một danh sách với một chu kỳ. Chu trình có độ dài nvà ban đầu chúng ta mcách các chu kỳ. Ngoài ra, hãy nói rằng điểm gặp gỡ là kbước ra khỏi chu kỳ bắt đầu và rùa và thỏ gặp nhau khi rùa đã thực hiện itổng số bước. (Hare sẽ thực hiện 2itổng số bước sau đó.).

2 điều kiện sau đây phải được giữ:

1) i = m + p * n + k

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

Người đầu tiên nói rằng rùa di chuyển icác bước và trong các ibước này, đầu tiên nó sẽ đến chu kỳ. Sau đó, nó đi qua pthời gian chu kỳ cho một số số dương p. Cuối cùng, nó đi qua knhiều nút hơn cho đến khi nó gặp thỏ rừng.

Một điều tương tự là đúng cho thỏ rừng. Nó di chuyển 2icác bước và trong các 2ibước này trước tiên nó sẽ đến chu kỳ. Sau đó, nó đi qua qthời gian chu kỳ cho một số số dương q. Cuối cùng, nó đi qua knhiều nút hơn cho đến khi gặp rùa.

Khi thỏ đi với tốc độ gấp đôi rùa, và thời gian là không đổi đối với cả hai khi chúng đến điểm hẹn.

Vì vậy, bằng cách sử dụng quan hệ tốc độ, thời gian và khoảng cách đơn giản,

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

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

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

Trong số m, n, k, p, q, hai cái đầu tiên là thuộc tính của danh sách đã cho. Nếu chúng ta có thể chỉ ra rằng có ít nhất một tập hợp các giá trị cho k, q, p làm cho phương trình này đúng, chúng ta chỉ ra rằng giả thuyết này là đúng.

Một bộ giải pháp như sau:

p = 0

q = m

k = m n - m

Chúng tôi có thể xác minh rằng các giá trị này hoạt động như sau:

m + k = ( q - 2p ) n  

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

=> mn = mn.

Đối với bộ này, i

i = m + p n + k

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

Tất nhiên, bạn sẽ thấy rằng đây không nhất thiết là nhỏ nhất tôi có thể. Nói cách khác, rùa và thỏ có thể đã gặp nhau trước đó nhiều lần. Tuy nhiên, vì chúng tôi cho thấy rằng họ gặp nhau tại một số điểm ít nhất một lần chúng tôi có thể nói rằng giả thuyết này là chính xác. Vì vậy, họ sẽ phải gặp nhau nếu chúng ta di chuyển một trong số họ 1 bước, và một bước còn lại 2 bước một lần.

Bây giờ chúng ta có thể đi đến phần thứ hai của thuật toán đó là cách tìm phần đầu của chu kỳ.

Bắt đầu chu kỳ

Khi rùa và thỏ gặp nhau, chúng ta hãy đưa rùa trở lại đầu danh sách và giữ thỏ ở nơi chúng gặp nhau (cách k bước ra khỏi chu kỳ bắt đầu).

Giả thuyết là nếu chúng ta để chúng di chuyển với cùng tốc độ (1 bước cho cả hai), lần đầu tiên chúng gặp lại sẽ là chu kỳ bắt đầu.

Hãy chứng minh giả thuyết này.

Trước tiên hãy giả sử một số lời sấm cho chúng ta biết m là gì.

Sau đó, nếu chúng ta cho chúng di chuyển các bước m + k, rùa sẽ phải đến điểm mà chúng gặp ban đầu (k bước ra khỏi chu kỳ bắt đầu - xem trong hình).

Trước đây chúng tôi đã cho thấy rằng m + k = (q - 2p) n.

Vì các bước m + k là bội số của độ dài chu kỳ n, nên, trong thời gian trung bình, sẽ đi qua chu kỳ (q-2p) và sẽ quay lại cùng một điểm (k bước ra khỏi chu kỳ bắt đầu).

Bây giờ, thay vì để chúng di chuyển các bước m + k, nếu chúng ta chỉ cho chúng di chuyển các bước m, rùa sẽ đến chu kỳ bắt đầu. Hare sẽ là k bước ngắn để hoàn thành các vòng quay (q-2p). Vì nó bắt đầu k bước trước chu kỳ bắt đầu, thỏ rừng sẽ phải đến chu kỳ bắt đầu.

Kết quả là, điều này giải thích rằng họ sẽ phải gặp nhau ở chu kỳ bắt đầu sau một số bước đầu tiên (lần đầu tiên vì rùa chỉ đến chu kỳ sau m bước và nó không bao giờ có thể thấy thỏ rừng đã ở trong đó chu kỳ).

Bây giờ chúng ta biết rằng số bước chúng ta cần để di chuyển chúng cho đến khi chúng gặp nhau hóa ra là khoảng cách từ đầu danh sách đến chu kỳ bắt đầu, m. Tất nhiên, thuật toán không cần biết m là gì. Nó sẽ chỉ di chuyển cả rùa và thỏ một bước cho đến khi chúng gặp nhau. Điểm gặp gỡ phải là bắt đầu chu kỳ và số bước phải là khoảng cách (m) đến chu kỳ bắt đầu. Giả sử chúng ta biết độ dài của danh sách, chúng ta cũng có thể, tính độ dài của chu kỳ trừ m từ chiều dài danh sách.


1
Tôi không nghĩ đúng như vậy khi họ gặp nhau, đó là điểm khởi đầu, hãy xem bình luận bên dưới: stackoverflow.com/a/19209858/1744146 <br> Xin vui lòng cho tôi biết Nếu tôi sai
MrA

Phần đầu tiên của lời giải thích là hoàn hảo. Nhưng phần thứ hai có một lỗ hổng theo như tôi biết. Bạn đang giả sử rằng "một số lời sấm nói m", nhưng nếu m được biết, bạn đã bắt đầu chu kỳ. Làm thế nào bạn có thể chỉ giả sử câu trả lời khi bạn không bao giờ biết bắt đầu chu kỳ ở đâu ?? Làm ơn cho tôi biết.
Gopichand

1
@Gopichand Đọc lại đoạn cuối cùng một lần nữa ... bạn chỉ cần giả sử rằng có một số m (nếu đã được chứng minh rằng có một chu kỳ) .. nhưng bạn không biết giá trị của m
Srinath

2
Bây giờ đây thực sự là một lời giải thích tuyệt vời. Đây có lẽ là lời giải thích tốt nhất hiện nay trên toàn bộ internet.
Arlene Batada

2
Phương trình của bạn m + k = (q - 2p) ncó thể được đơn giản hóa hơn nữa m + k = q*n. Điều này là do số vòng lặp mà rùa mất sẽ luôn bằng không vì thỏ rừng không bao giờ có thể vượt qua rùa mà không gặp nó. Hãy suy nghĩ về nó.
Arpit Jain

124

Tham khảo hình ảnh này:

nhập mô tả hình ảnh ở đây

Khoảng cách di chuyển của SlowPulum trước khi gặp = x + y

Khoảng cách di chuyển của fastPulum trước khi gặp = (x + y + z) + y = x + 2y + z

Vì fastPulum di chuyển với tốc độ gấp đôi tốc độ của SlowPulum và thời gian là không đổi cho cả hai khi đến điểm gặp gỡ.

Vì vậy, bằng cách sử dụng tốc độ đơn giản, thời gian và khoảng cách quan hệ 2 (x + y) = x + 2y + z => x + 2y + z = 2x + 2y => x = z

Do đó bằng cách di chuyển SlowPulum để bắt đầu danh sách được liên kết và làm cho cả SlowPulum và fastPulum để di chuyển một nút tại một thời điểm, cả hai đều có cùng khoảng cách để che .

Họ sẽ đạt đến điểm mà vòng lặp bắt đầu trong danh sách được liên kết.


10
Điều này không tính đến trường hợp fastPulum di chuyển theo chu kỳ n lần trước khi SlowPulum đi vào chu kỳ. Sử dụng l để biểu thị độ dài của chu kỳ. Khoảng cách di chuyển của fastPulum trước khi gặp = (x + y + z) + y = x + 2y + nl + z. Và mối quan hệ kết quả sẽ là x = nl + z.
Jingguo Yao

@JingguoYao: Đây là lời giải thích cho trường hợp đó.
displayName

2
sơ đồ này là quá đơn giản. con trỏ nhanh có thể di chuyển nhiều lần trong chu kỳ trước khi con trỏ chậm chạm tới nó.
Warren MacEvoy

70

Câu trả lời đơn giản và không được đánh giá cao của Old Monk giải thích việc tìm chu kỳ khi người chạy nhanh hoàn thành chỉ một chu kỳ đầy đủ. Trong câu trả lời này, tôi giải thích trường hợp khi người chạy nhanh đã chạy vòng lặp nhiều lần trước khi người chạy chậm vào vòng lặp.


Sử dụng cùng một hình ảnh:nhập mô tả hình ảnh ở đây

Giả sử người chạy nhanh đã chạy vòng lặp m lần trước khi gặp nhau chậm và nhanh. Điều này có nghĩa rằng:

  • Khoảng cách chạy chậm: x + y
  • Khoảng cách chạy nhanh: x + m (y + z) + y tức là thêm y nơi họ gặp nhau

Vì chạy nhanh với tốc độ chậm gấp đôi và chúng chạy cùng một lúc, điều đó ngụ ý rằng nếu chúng ta tăng gấp đôi khoảng cách chạy chậm, chúng ta sẽ có được quãng đường chạy nhanh. Như vậy

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

Giải cho x cho,

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

Trong kịch bản thực, điều đó có nghĩa là, x = (m - 1) vòng lặp hoàn chỉnh chạy + thêm một khoảng cách z .

Do đó, nếu chúng ta đặt một con trỏ ở đầu danh sách và để con trỏ kia ở điểm gặp gỡ, thì việc di chuyển chúng với cùng tốc độ sẽ dẫn đến con trỏ trong vòng lặp hoàn thành m - 1 lần chạy của vòng lặp và sau đó gặp người khác con trỏ ngay tại vòng lặp bắt đầu.


7
Một nghi ngờ .. làm thế nào đảm bảo rằng chậm và nhanh sẽ đáp ứng trước khi chậm mất nhiều hơn một chu kỳ?
siraj

4
@siraj: Chậm sẽ không chạy theo chu kỳ, nhanh vì nó chạy nhanh hơn chậm và sẽ vào vòng lặp trước. Và nó đảm bảo rằng họ sẽ gặp nhau. Nếu chậm là ở j + 1 và nhanh là ở j, thì bây giờ họ sẽ gặp nhau ở j + 2. Và nếu chậm ở j và nhanh ở j + 1, điều đó có nghĩa là họ đã gặp nhau ở j - 1.
displayName

4
toán học vẫn hoạt động nếu chậm đi vòng lặp: x + (y + z) m + y = 2 (x + (y + z) n + y), trong đó n là # lần xung quanh vòng lặp cho chậm trước khi chúng gặp nhau. Điều này giải quyết thành (m - 2n - 1) (y + z) + z = x. Có nghĩa là bắt đầu tại điểm gặp gỡ, đi xung quanh (m-2n-1) lần, bạn quay lại điểm gặp gỡ, sau đó đi z, bạn đang bắt đầu vòng lặp. Và để làm điều này, nó giống như bắt đầu từ nút đầu và đi x nút.
mayas_mom

1
@mayas_mom: Toán học có thể được giải quyết nhưng chậm sẽ không bao giờ có thể đi vòng vòng. Nó sẽ luôn bị bắt ngay khi bắt đầu hoặc ở đâu đó giữa chừng.
displayName

4
x = (m - 1) (y + z) + z điều này có thể được khái quát hóa vì độ dài vòng lặp là y + z và vì chỉ quan tâm đến vị trí. Vậy x = ((m - 1) (y + z))% (y + z)) + z Đó là hiệu quả x = z;
anshul garg

10

Nó rất đơn giản. Bạn có thể nghĩ về tốc độ tương đối. Nếu thỏ di chuyển hai nút và rùa di chuyển một nút, thì tương đối với thỏ rùa đang di chuyển một nút (giả sử rùa ở trạng thái nghỉ). Vì vậy, nếu chúng ta di chuyển một nút trong danh sách liên kết tròn, chúng ta chắc chắn sẽ gặp lại nhau tại thời điểm đó.

Sau khi tìm thấy điểm được kết nối bên trong danh sách liên kết tròn, bây giờ vấn đề được giảm xuống thành việc tìm điểm giao nhau của hai vấn đề danh sách được liên kết.


8

Hình 1

Vào thời điểm va chạm đầu tiên, rùa đã di chuyển m + k như hiển thị ở trên. Thỏ di chuyển nhanh gấp đôi rùa, nghĩa là thỏ di chuyển 2 (m + k) bước. Từ những sự kiện đơn giản này, chúng ta có thể rút ra biểu đồ sau.

Hình 1

Tại thời điểm này, chúng tôi di chuyển rùa trở lại từ đầu và tuyên bố rằng cả thỏ và rùa phải di chuyển từng bước một. Theo định nghĩa, sau m bước, rùa sẽ ở đầu chu kỳ. Nơi nào sẽ thỏ rừng?

Thỏ cũng sẽ ở đầu chu kỳ. Điều này là rõ ràng từ biểu đồ thứ hai: Khi rùa được di chuyển trở lại từ đầu, thỏ rừng đã bước k vào chu kỳ cuối cùng của nó. Sau m bước, thỏ rừng sẽ hoàn thành một chu kỳ khác và va chạm với rùa.


@WarrenMacEvoy Tôi không đề nghị họ gặp nhau ở điểm bắt đầu. Họ gặp lại nhau khi bắt đầu chu kỳ khi các số liệu chỉ ra rõ ràng.
skedastik

5

Tiếp cận:

Có hai con trỏ:

  • Một con trỏ chậm di chuyển một nút tại một thời điểm.
  • Một con trỏ nhanh di chuyển hai nút cùng một lúc.

Nếu hai con trỏ gặp nhau, nó chứng tỏ rằng có một vòng lặp. Một khi họ đã gặp nhau, một trong các nút sẽ trỏ đến đầu và sau đó cả hai tiến hành một nút tại một thời điểm. Họ sẽ gặp nhau khi bắt đầu vòng lặp.

Cơ sở lý luận: Khi hai người đi xuống một đường ray tròn, một trong số họ với tốc độ gấp đôi người kia, họ gặp nhau ở đâu? Chính xác nơi họ bắt đầu.

Bây giờ, giả sử người chạy nhanh có một kbước khởi đầu trong một nbước trong vòng. họ sẽ gặp nhau ở đâu Chính xác tại n-kcác bước. Khi người chạy chậm có (n-k)các bước được bảo hiểm , người chạy nhanh sẽ có k+2(n-k)các bước được bảo hiểm . ( tức là k+2n-2kcác bước tức là 2n-kcác bước ). I E(n-k) các bước (Đường dẫn có hình tròn và chúng tôi không quan tâm đến số vòng mà sau đó họ gặp nhau; Chúng tôi chỉ quan tâm đến vị trí mà họ gặp nhau).

Bây giờ làm thế nào để người chạy nhanh có được sự khởi đầu của k các bước ở vị trí đầu tiên? Bởi vì nó đã chạy chậm mà nhiều bước để đạt đến điểm bắt đầu của vòng lặp. Vì vậy, bắt đầu của vòng lặp là k bước từ nút đầu.

Lưu ý: Nút nơi cả hai con trỏ gặp nhau kcách bước bắt đầu của vòng lặp (bên trong vòng lặp) và nút đầu cũng làk cách bước bắt đầu của vòng lặp. Vì vậy, khi chúng ta có con trỏ tiến với tốc độ bằng 1 bước từ bot các nút này, chúng sẽ gặp nhau khi bắt đầu vòng lặp.

Tôi tin rằng nó là đơn giản. Xin vui lòng cho tôi biết nếu bất kỳ phần nào là mơ hồ.


4
Vui lòng gửi câu trả lời đầy đủ ở đây thay vì chỉ một liên kết có thể bị
hỏng

4

Được rồi, giả sử thỏ và rùa gặp nhau tại một điểm cách k bắt đầu của chu kỳ, số bước trước khi chu kỳ bắt đầu là mu và độ dài của chu kỳ là L.

Vì vậy, bây giờ tại điểm họp ->

Khoảng cách được bao phủ bởi rùa = mu + a * L + k - Phương trình 1

(Các bước được thực hiện để bắt đầu chu kỳ + các bước được thực hiện để bao gồm 'a' các bước lặp của chu trình + k bước từ đầu chu kỳ) (trong đó a là một hằng số dương)

Khoảng cách được bao phủ bởi thỏ = mu + b * L + k - Phương trình 2

(Các bước được thực hiện để bắt đầu chu kỳ + các bước được thực hiện để bao gồm các lần lặp 'b' của chu kỳ + k bước từ đầu chu kỳ) (trong đó b là một hằng số dương và b> = a)

Vì vậy, khoảng cách thêm được bao phủ bởi thỏ là = Phương trình 2 - Phương trình 1 = (ba) * L

Xin lưu ý rằng khoảng cách này cũng bằng khoảng cách của rùa từ điểm bắt đầu vì thỏ di chuyển nhanh hơn 2 lần so với rùa. Điều này có thể được tương đương với 'mu + k', đó cũng là khoảng cách của điểm gặp gỡ từ đầu nếu chúng ta không bao gồm nhiều lần di chuyển của chu kỳ.

Do đó, mu + k = (ba) * L

Vì vậy, các bước mu từ thời điểm này sẽ dẫn trở lại đầu chu kỳ (vì k bước từ đầu chu kỳ đã được thực hiện để đạt đến điểm gặp gỡ). Điều này có thể xảy ra trong cùng một chu kỳ hoặc bất kỳ chu kỳ tiếp theo nào. Vì vậy, bây giờ nếu chúng ta di chuyển con rùa đến đầu danh sách được liên kết, nó sẽ thực hiện các bước để đạt đến điểm bắt đầu của chu kỳ và thỏ rừng sẽ thực hiện các bước để đến đầu chu kỳ và do đó cả hai sẽ gặp nhau tại điểm bắt đầu của chu kỳ.

PS Thành thật mà nói, tôi có câu hỏi giống như poster ban đầu trong đầu và tôi đã đọc câu trả lời đầu tiên, họ đã làm rõ một vài điều nhưng tôi không thể đi đến kết quả cuối cùng một cách rõ ràng và vì vậy tôi đã cố gắng làm theo cách của mình và tìm thấy nó dễ hiểu hơn


họ thường không gặp nhau vào đầu chu kỳ
Warren MacEvoy

3

nhập mô tả hình ảnh ở đây tín dụng hình ảnh

Gọi khoảng cách số lượng liên kết mà một con trỏ theo sau và thời gian số lần lặp mà thuật toán cần để di chuyển con trỏ chậm một liên kết và con trỏ nhanh hai liên kết. Có N nút trước một chu kỳ có độ dài C, được dán nhãn với chu kỳ bù k = 0 đến C-1.

Để đạt đến điểm bắt đầu của chu kỳ, chậm cần N thời gian và khoảng cách. Điều này có nghĩa là nhanh chóng mất khoảng cách N trong chu kỳ (N để đến đó, N để quay). Vì vậy, tại thời điểm N, chậm là ở chu kỳ bù k = 0 và nhanh là ở chu kỳ bù k = N mod C.

Nếu N mod C bằng 0, chậm và nhanh thì khớp và chu trình được tìm thấy tại thời điểm N và vị trí chu kỳ k = 0.

Nếu N mod C không bằng 0, thì nhanh bây giờ phải bắt kịp với tốc độ chậm, tại thời điểm N là khoảng cách C- (N mod C) phía sau trong chu kỳ.

Vì nhanh di chuyển 2 cho mỗi 1 chậm, giảm khoảng cách 1 trên mỗi lần lặp, nên việc này mất nhiều thời gian hơn so với khoảng cách giữa nhanh và chậm tại thời điểm N, đó là C- (N mod C). Vì chậm di chuyển từ offset 0, đây cũng là offset mà chúng gặp nhau.

Vì vậy, nếu N mod C bằng 0, giai đoạn 1 dừng sau khi lặp N ở đầu chu kỳ. Mặt khác, pha 1 dừng sau các lần lặp N + C- (N mod C) tại offset C- (N mod C) vào chu kỳ.

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

Ok, vì vậy giai đoạn 2: chậm mất N bước nữa để đến chu kỳ, tại đó điểm nhanh (hiện đang di chuyển 1 trên bước thời gian) là tại (C- (N mod C) + N) mod C = 0. Vì vậy, họ gặp nhau vào đầu chu kỳ sau giai đoạn 2.

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

Để hoàn thiện, giai đoạn 3 tính toán độ dài chu kỳ bằng cách di chuyển một lần nữa qua chu kỳ:

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

Liên kết với tài liệu google để mô phỏng thuật toán: docs.google.com.vn/s
dàn tính / d / Từ

1
Lưu ý rằng, nếu N <= C, phép lặp dừng sau lần lặp C. Trong mọi trường hợp, nó phải dừng ở ít hơn các bước N + C và không có khả năng dừng lại ở đầu chu kỳ.
Warren MacEvoy

2

Giảm vấn đề thành vấn đề lặp, sau đó quay lại vấn đề ban đầu

Tôi tìm thấy lời giải thích sau đây trực quan hơn.

  1. Lấy hai con trỏ ( 1 = rùa và 2 = thỏ) bắt đầu từ đầu ( O ), 1 có chiều dài bước 1 , 2 có chiều dài bước là 2 . Hãy nghĩ về thời điểm khi 1 đến nút bắt đầu của chu kỳ đó ( A ).

    Chúng tôi muốn trả lời cho câu hỏi sau "2 ở đâu khi 1 trong A?" .

    Vì vậy, OA = alà một số tự nhiên ( a >= 0). Nhưng nó có thể được viết theo cách sau : a = k*n + b, trong đó a, k, n, b are natural numbers:

    • n = chiều dài chu kỳ
    • k >= 0 = hằng số
    • 0 <= b <= n-1

    Nó có nghĩa là b = a % n.

    Ví dụ: if a = 20n = 8=> k = 2b = 4bởi vì 20 = 2*8 + 4.

    Khoảng cách được bao phủ bởi 1d = OA = a = k*n + b. Nhưng trong cùng một lúc, 2 bìa D = 2*d = d + d = OA + d = OA + k*n + b. Điều này có nghĩa là khi 2 nằm trong A thì nó phải che lại k*n + b. Như bạn có thể thấy, klà số vòng, nhưng sau những vòng đua, 2 sẽ b xa A. Vì vậy, chúng tôi tìm thấy nơi 2 là khi 1 trong A. Hãy gọi điểm đó B, nơi AB = b.

    nhập mô tả hình ảnh ở đây

  2. Bây giờ, chúng tôi giảm vấn đề thành một vòng tròn. Câu hỏi là "Điểm gặp gỡ ở đâu?" . C đó ở đâu?

    nhập mô tả hình ảnh ở đây

    Trong mỗi bước, 2 giảm khoảng cách từ 1 với 1(giả sử là đồng hồ đo) vì 1 đang tiến xa hơn từ 2 với 1, nhưng đồng thời 2 tiến gần hơn đến 1 bằng 2.

    Vì vậy, giao điểm sẽ là khi khoảng cách giữa 12 sẽ bằng không. Điều này có nghĩa là 2 giảm n - bkhoảng cách. Để đạt được điều này, 1 sẽ thực hiện n - bcác bước, trong khi 2 sẽ thực hiện 2*(n - b)các bước.

    Vì vậy, điểm giao nhau sẽ n - bcách xa A (theo chiều kim đồng hồ), vì đây là khoảng cách được bao phủ bởi 1 cho đến khi gặp 2 . => khoảng cách giữa CACA = b, bởi vì AC = AB + BC = n - bCA = n - AC. Đừng nghĩ rằng AC = CA, bởi vì ACkhoảng cách không phải là khoảng cách toán học tầm thường, đó là số bước giữa AC (trong đó A là điểm bắt đầu và C là điểm kết thúc).

  3. Bây giờ, hãy quay trở lại lược đồ ban đầu.

    Chúng tôi biết rằng a = k*n + bCA = b.

    Chúng ta có thể lấy 2 con trỏ mới 1 '1' ' , trong đó 1' bắt đầu từ đầu ( O ) và 1 '' bắt đầu từ điểm giao nhau ( C ).

    Trong khi 1 ' đi từ O đến A , 1' ' đi từ C đến A và tiếp tục hoàn thành kvòng đua. Vì vậy, các điểm giao nhau là Một .

    nhập mô tả hình ảnh ở đây

    nhập mô tả hình ảnh ở đây


2

nhập mô tả hình ảnh ở đây

Nếu các con trỏ gặp nhau tại một điểm P như trong hình, khoảng cách Z + Y là điểm P và X + Y cũng là điểm P có nghĩa là Z = X. Đó là lý do tại sao tiếp tục di chuyển một con trỏ từ P và di chuyển một con trỏ khác từ bắt đầu (S) cho đến khi chúng gặp nhau, có nghĩa là di chuyển một khoảng cách bằng nhau (Z hoặc X) đến cùng một điểm M (khoảng cách Z từ P và X từ S) sẽ là bắt đầu vòng lặp. Đơn giản!


1

Với tất cả các phân tích ở trên, nếu bạn là một người học tập, tôi đã cố gắng viết ra một phân tích ngắn và ví dụ giúp giải thích toán học mà mọi người khác cố gắng giải thích. Chúng ta đi đây!

Phân tích:

Nếu chúng ta có hai con trỏ, một nhanh hơn cái kia và di chuyển chúng cùng nhau, cuối cùng chúng sẽ gặp lại nhau để chỉ ra một chu kỳ hoặc null để chỉ ra không có chu kỳ.

Để tìm điểm bắt đầu của chu kỳ, hãy ...

  1. m là khoảng cách từ đầu đến đầu chu kỳ;

  2. d là số lượng nút trong chu kỳ;

  3. p1 là tốc độ của con trỏ chậm hơn;

  4. p2là tốc độ của con trỏ nhanh hơn, vd. 2 có nghĩa là các bước thông qua hai nút tại một thời điểm.

    Quan sát các lần lặp sau:

 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

Từ dữ liệu mẫu ở trên, chúng ta có thể dễ dàng phát hiện ra rằng bất cứ khi nào con trỏ nhanh hơn và chậm hơn gặp nhau, chúng đều mcách bước bắt đầu của chu kỳ. Để giải quyết điều này, đặt con trỏ nhanh hơn trở lại ở đầu và đặt tốc độ của nó thành tốc độ của con trỏ chậm hơn. Khi họ gặp lại nhau, nút là bắt đầu của chu kỳ.


1

hãy cùng nói nào,

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

chúng ta có 2 con trỏ A và B, A chạy ở tốc độ 1x, B ở tốc độ gấp đôi, cả hai đều bắt đầu từ đầu.

khi A đạt N [0], B phải ở trong N [m]. (Lưu ý: A sử dụng m bước để đạt N [0] và B nên thêm m bước nữa)

Sau đó, A chạy thêm k bước nữa để va chạm với B, tức là A ở N [k], B ở N [m + 2k] (Lưu ý: B nên chạy trong 2k bước bắt đầu từ N [m])

A va chạm B tại N [k] và N [m + 2k], có nghĩa là k = m + 2k, do đó k = -m

Do đó, để quay trở lại N [0] từ N [k], chúng ta cần thêm m bước nữa.

Nói một cách đơn giản, chúng ta chỉ cần chạy thêm m bước nữa sau khi tìm thấy nút va chạm. Chúng ta có thể có một con trỏ để chạy từ đầu và một con trỏ chạy từ nút va chạm, chúng sẽ gặp nhau tại N [0] sau m bước.

Do đó, mã giả như sau:

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

Tôi không nghĩ đúng như vậy khi họ gặp nhau đó là điểm khởi đầu. Nhưng có nếu con trỏ khác (F) đã ở điểm gặp gỡ trước đó, thì con trỏ đó sẽ ở cuối vòng lặp thay vì bắt đầu vòng lặp và con trỏ (S) bắt đầu từ đầu danh sách, nó sẽ bắt đầu từ đầu danh sách kết thúc ở đầu vòng lặp. ví dụ:

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

Một lời giải thích đơn giản sử dụng ý tưởng về vận tốc tương đối được dạy ở trường trung học - Bài giảng Vật lý 101 / Động học.

Vòng tròn trong LinkedList

  1. Giả sử khoảng cách từ đầu danh sách được liên kết đến đầu vòng tròn là xbước nhảy. Chúng ta hãy gọi điểm bắt đầu của vòng tròn là điểm X(tính theo mũ - xem hình trên). Ngoài ra, giả sử tổng kích thước của vòng tròn là N bước nhảy.

  2. Tốc độ thỏ rừng = 2 * Tốc độ của rùa. Vì vậy, đó là 1 hops/sec2 hops/sectương ứng

  3. Khi rùa đến điểm bắt đầu của vòng tròn X, thỏ rừng phải xđi xa hơn tại điểm Ytrong hình. (Vì thỏ rừng đã đi được quãng đường gấp đôi con rùa).

  4. Do đó, chiều dài của cung còn lại theo chiều kim đồng hồ từ X đến Y sẽ là N-x. T của anh ta cũng là khoảng cách tương đối được che giữa thỏ rừng và rùa để họ có thể gặp nhau . Giả sử khoảng cách tương đối này sẽ được bảo hiểm theo thời gian t_mtức là thời gian gặp nhau. Tốc độ tương đối là (2 hops/sec - 1 hops/sec)tức là 1 hops/sec. Do đó, sử dụng khoảng cách tương đối = tốc độ tương đối X thời gian, chúng tôi nhận được, t= N-xgiây. Vì vậy, nó sẽ mất N-xđể đạt đến điểm gặp gỡ cho cả rùa và thỏ rừng.

  5. Bây giờ trong N-xthời gian thứ hai và ở 1 hops/sectốc độ, con rùa trước đó tại điểm Xsẽ bao gồm hoa bia Nx để đến điểm gặp gỡ M. Vì vậy, điều đó có nghĩa là điểm gặp gỡ MN-xbước nhảy ngược chiều kim đồng hồ từ X= (điều này ngụ ý thêm) => có xkhoảng cách còn lại từ điểm Mđến Xchiều kim đồng hồ.

  6. Nhưng xcũng là khoảng cách để đạt được điểm Xtừ đầu danh sách được liên kết.

  7. Bây giờ, chúng tôi không quan tâm số lượng hoa bia xtương ứng với. Nếu chúng ta đặt một con rùa ở đầu LinkedList và một con rùa ở điểm gặp gỡ Mvà để chúng nhảy / đi, thì chúng sẽ gặp nhau tại điểm X, đó là điểm (hoặc nút) mà chúng ta cần.


1

Làm việc này với một sơ đồ sẽ giúp. Tôi đang cố gắng giải thích vấn đề mà không có phương trình.

  1. Nếu chúng ta để thỏ và rùa chạy thành vòng tròn và thỏ chạy hai lần rùa thì cuối một vòng dành cho rùa thỏ sẽ ở một nửa. Khi kết thúc hai vòng đua từ rùa thỏ sẽ thực hiện 1 vòng và cả hai gặp nhau. Điều này áp dụng cho tất cả các tốc độ như nếu thỏ chạy ba lần, thỏ 1 vòng bằng 1/3 rùa nên cuối 3 vòng cho thỏ thỏ sẽ che được 1 vòng và chúng gặp nhau.
  2. Bây giờ nếu chúng ta bắt đầu chúng m bước trước vòng lặp, thì điều đó có nghĩa là thỏ rừng nhanh hơn đang bắt đầu trước vòng lặp. Vì vậy, nếu rùa bắt đầu vòng lặp, thỏ rừng là m bước trước vòng lặp và khi chúng gặp nhau, đó sẽ là bước m trước khi vòng lặp bắt đầu.

1

-có các bước k trước vòng lặp. Chúng tôi không biết k là gì và không cần phải tìm hiểu. Chúng ta có thể làm việc trừu tượng chỉ với k.

--Sau k bước

----- T đang ở chu kỳ bắt đầu

----- H là k bước vào chu kỳ (anh ấy đã đi tổng cộng 2k và do đó k vào vòng lặp)

** bây giờ họ đang loops - k ngoài

(lưu ý rằng k == K == mod (loopsize, k) --eg nếu một nút có 2 bước trong chu kỳ 5 nút thì nó cũng là 7, 12 hoặc 392 bước, vì vậy chu kỳ là bao nhiêu thì wrt k không yếu tố trong.

Vì chúng bắt kịp nhau với tốc độ 1 bước trên một đơn vị thời gian vì một con chuyển động nhanh gấp đôi so với con kia, chúng sẽ gặp nhau ở vòng lặp - k.

Điều này có nghĩa là nó sẽ đưa k nút đến điểm bắt đầu của chu kỳ và do đó khoảng cách từ đầu đến cyclestart và va chạm đến cyclestart là như nhau.

Vì vậy, bây giờ sau khi va chạm đầu tiên di chuyển T trở lại đầu. T và H sẽ gặp nhau ở cyclestart nếu bạn di chuyển với tốc độ 1 mỗi cái. (trong k bước cho cả hai)

Điều này có nghĩa là thuật toán là:

  • từ đầu di chuyển T = t.next và H.next.next cho đến khi chúng va chạm (T == H) (có một chu kỳ)

// chăm sóc trường hợp khi k = 0 hoặc T và H gặp nhau ở đầu vòng lặp bằng cách tính độ dài của vòng lặp

- đếm chiều dài của chu kỳ bằng cách di chuyển T hoặc H xung quanh nó bằng bộ đếm

- di chuyển một con trỏ T2 đến đầu danh sách

- chiều dài con trỏ của các bước chu kỳ

- di chuyển con trỏ H2 khác đến đầu

- di chuyển T2 và H2 song song cho đến khi chúng gặp nhau khi bắt đầu chu kỳ

đó là nó!


1

Đã có rất nhiều câu trả lời cho vấn đề này, nhưng tôi đã từng đưa ra một sơ đồ cho điều này trực quan hơn với tôi. Có lẽ nó có thể giúp đỡ người khác.

Những khoảnh khắc chính đối với tôi là:

  • Tách T (rùa) thành T1 (vòng lặp trước) và T2 (vòng lặp). T = rùa, H = thỏ

  • Trừ T khỏi H , trong đó chúng trùng nhau về mặt trực quan. Còn lại gì ( H - T = H' ) là tương đương với T .

  • Toán học còn lại khá đơn giản. Từ H, trừ đi T chồng chéo trực quan

-1

Tôi biết đã có một câu trả lời được chấp nhận cho vấn đề này nhưng tôi vẫn sẽ cố gắng trả lời một cách trôi chảy. Giả định :

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.

Bây giờ, hãy để thỏ rừng và rùa gặp nhau sau thời gian bắt đầu.

Quan sát:

Nếu, Khoảng cách di chuyển của rùa = v * t = x + (bk) (nói)

Sau đó, Khoảng cách di chuyển của thỏ = 2 * v * t = x + (b - k) + b (vì thỏ đã đi qua phần được lặp một lần rồi)

Bây giờ, có thời gian gặp mặt là như nhau.

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

=> x = k

Tất nhiên điều này có nghĩa là độ dài của đường dẫn không được lặp giống như khoảng cách của điểm bắt đầu của vòng lặp từ điểm mà cả hai gặp nhau.


Bạn không thể cho rằng rùa di chuyển chính xác x + bk vào thời điểm chúng gặp nhau. Ngoài ra, tôi không hiểu làm thế nào bạn có x + 2 * bk cho khoảng cách thỏ rừng.
Máy phát điện

Bởi vì thỏ rừng đã đi qua phần bị lặp một lần để phải gặp rùa .. Tôi đã không giải thích nó ở đó: /
n0nChun

-1

Thật sự dễ dàng để chứng minh rằng cả hai sẽ gặp nhau ở điểm bắt đầu, nếu bạn xem xét các toán học đằng sau điểm gặp gỡ.
Đầu tiên hãy để m biểu thị điểm bắt đầu của chu kỳ trong danh sách được liên kết và n biểu thị độ dài của chu kỳ. Sau đó, để thỏ và rùa gặp nhau, chúng ta có:

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

Nói rõ hơn về mặt toán học:

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

vì vậy chúng sẽ gặp nhau tại thời điểm t nên là bội số của chu kỳ. Điều này có nghĩa là họ gặp nhau tại một địa điểm (t-m) modulo n = (0-m) modulo n = (-m) modulo n.

Vì vậy, bây giờ trở lại câu hỏi, nếu bạn di chuyển một con trỏ từ đầu danh sách được liên kết và một con trỏ khác từ điểm giao nhau, sau m bước chúng ta sẽ có thỏ (đang di chuyển bên trong chu kỳ) đến một điểm ((-m) + m) modulo n = 0 modulo nđó là gì, nhưng điểm bắt đầu của cycle.So chúng ta có thể thấy rằng sau khi bước m nói đến sự bắt đầu của chu kỳ và rùa sẽ gặp nó ở đó vì nó sẽ đi qua m bước từ khi bắt đầu của danh sách liên kết.

Là một mặt lưu ý, chúng ta cũng có thể tính toán thời gian giao nhau của họ theo cách này: Điều kiện t = 0 modulo ncho chúng ta biết rằng họ sẽ gặp nhau tại một thời điểm mà là một bội số của độ dài chu kỳ, và cũng t phải lớn hơn m là họ sẽ gặp nhau ở chu kỳ . Vì vậy thời gian thực hiện sẽ bằng bội số đầu tiên của n lớn hơn m .


Họ không nhất thiết phải gặp nhau khi bắt đầu chu kỳ.
Warren MacEvoy

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.