LeetCode | 141 linked list cycle

Neking發表於2024-08-04

https://github.com/dolphinmind/datastructure/tree/datastructure-linkedlist

分析

證明過程

基本假設

  • 假設環的長度為(C)
  • 假設從連結串列的頭部到環的入口點的距離為(A)
  • 假設從環的入口點到快慢指標第一次相遇點的距離為(B)
  • 假設從快慢指標第一次相遇點回到環的入口點的距離為(C-B)

證明過程

  1. 慢指標的移動
  • 慢指標每次移動一步
  • 當慢指標進入環後,它會沿著環移動,直到與快指標相遇
  1. 快指標的移動
  • 快指標每次移動兩步
  • 當快指標進入環後,它也會沿著環移動,直到與慢指標相遇
  1. 相遇點分析
  • 當快指標和慢指標相遇時,假設慢指標走了(x)步,那麼快指標走了(2x)步
  • 慢指標從連結串列頭部到相遇點的距離為(A+B+rC),其中(r)是慢指標在環內繞圈的次數
  • 快指標從連結串列頭部到相遇點的距離為(A+B+kC),其中(k)是快指標在環內繞圈的次數
  • 因為快指標的速度是慢指標的兩倍,所以快指標走的距離是慢指標的兩倍,即2(A+B+rC) = A+B+kC
  1. 求解方程
  • 從上述方程可以得出A + B + rC = |k-r|C => A + B = C + hC
  • 這意味著慢指標走過的距離 (A+B+rC)是環長度(C)的整數倍
  • 由於 (A+B+rC)是慢指標從連結串列頭部到相遇點的距離,而(|k-r|C)是快指標在環內繞圈的總長度,這意味著快指標和慢指標在環內相遇

這時可以發現快指標離環入口只需要走(C-B) + hC 距離,與連結串列的頭部到環入口距離一致,將快指標回填到連結串列頭部,類似於尾對齊發,即找到了相交點

主類

package com.github.dolphinmind.linkedlist;

import com.github.dolphinmind.linkedlist.uitls.ListNode;

/**
 * @author dolphinmind
 * @ClassName LinkedListCycle
 * @description 141. 環形連結串列
 * @date 2024/8/4 slow的速度v = 1
 *                fast的速度v = 2
 *                在沒有環的情況下,fast會最先到達末尾,從而返回false
 *                在有環的情況下,  fast在未進入環之前的情況和上述類似,fast進入環之後,fast開始在環內轉圈
 *                直到slow也進入圈內,兩者的相對速度為v = 1,此時fast指標反追擊slow,直到fast追擊到slow為止
 *                剛剛在思考的時候,突然想起連結串列相交的問題:發覺160連結串列相交問題與當前141環形連結串列問題有一定的相似性
 *
 *                假設 headA = 1->2->3->4
 *                    headB = 5->6->7->8->9->4
 *
 *                    slow  = 1->2->3->4->5->6->7->8->9->4
 *                    fast  = 5->6->7->8->9->4->1->2->3->4
 *
 *                  head = 1->2->3->4->5->6->7->8->4
 *                  slow = 1->2->3->4->5->6->7->8->4->5->6
 *                  fast = 1->3->5->7->4->6->8->5->7->4->6
 */

public class LinkedListCycle {

    /**
     * 雙指標法
     * @param head
     * @return
     */
    public boolean hasCycleTowPointer(ListNode<?> head) {

        if (head == null || head.next == null) {
            return false;
        }

        ListNode<?> slow = head;
        ListNode<?> fast = head;

        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;

            if (slow == fast) {
                return true;
            }
        }

        return false;

    }



}


相關文章