[LeetCode]142. 環形鏈表 II

題目

給定一個鏈表,返回鏈表開始入環的第一個節點。 若是鏈表無環,則返回 null。網絡

爲了表示給定鏈表中的環,咱們使用整數 pos 來表示鏈表尾鏈接到鏈表中的位置(索引從 0 開始)。 若是 pos 是 -1,則在該鏈表中沒有環。指針

說明:不容許修改給定的鏈表。code

來源:力扣(LeetCode)
連接:https://leetcode-cn.com/problems/linked-list-cycle-ii
著做權歸領釦網絡全部。商業轉載請聯繫官方受權,非商業轉載請註明出處。索引

題解

  • step1 使用快慢指針判斷有無環。使每次快指針走2步,慢指針走1步。
    • PS 兩指針並不必定在慢指針走環形第一圈就相遇。當非環形部分很長,環形一圈很短的狀況易見。
    • 若快指針每次走三步,若慢指針進入環形後,兩支針相差奇數圈,但每次快追慢距離爲2,則永遠不可能追上。(待驗證結論正確性?)
  • step2 畫圖理解。
    • 設鏈表起點到環形起點的距離爲x,環形起點到快慢指針相遇點距離爲y,環形的長度爲c。由同一時刻快指針是慢指針走的距離2倍,有2*(x+n1*c+y)=x+n2*c+y
    • <=> x+y=(n2-n1)*c ,理解式子含義爲從環中任意一點走x+y步,還能回到這點
    • =>(從起始點走了y步的)在相遇點的指針再走x步,還能回到環形起始點
    • 故讓在相遇點的慢指針再走x步便可找到環形入口

代碼

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode detectCycle(ListNode head) {
        // 判斷有無環
        ListNode fast = head;
        ListNode slow = head;
        boolean hasCycleFlag = false;
        while (fast != null && fast.next != null) {//
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) {
                hasCycleFlag = true;
                break;
            }
        }

        // 若無環直接返回null,不然找到環的起點並返回
        if (!hasCycleFlag) {
            return null;
        } else {
            ListNode p = head;
            while (p != slow) {
                p = p.next;
                slow = slow.next;
            }
            return p;
        }
    }
}
相關文章
相關標籤/搜索