剑指 Offer II 022. 链表中环的入口节点

题目:给定一个链表,返回链表开始入环的第一个节点。 从链表的头节点开始沿着 next 指针进入环的第一个节点为环的入口节点。如果链表无环,则返回 null。
思路:

  • 假设快慢指针相遇时,慢指针slow走了k步,那么快指针fast一定走了2k步


    image.png
  • fast一定比slow多走了k步,这多走的k步其实就是fast指针在环里转圈圈,所以k的值就是环长度的「整数倍」
  • 假设环的起点到相遇点的距离为m,见下图,环的起点距头结点head的距离为k - m,也就是说如果从head前进k - m步就能到达环起点。
  • 如果从相遇点继续前进k - m步,也恰好到达环起点。因为结合上图的 fast 指针,从相遇点开始走k步可以转回到相遇点,那走k - m步肯定就走到环起点了


    image.png
  • 只要我们把快慢指针中的任一个重新指向head,然后两个指针同速前进,k - m步后一定会相遇,相遇之处就是环的起点了
  • 在寻找相遇点时,slow和fast的初始必须是head.next和slow.next,不然就无法满足从head出发

public class Solution {
    private ListNode oneNode(ListNode head){
        if(head == null || head.next==null){
            return null;
        }
        ListNode slow = head.next;//slow在head.next,,不能是head
        ListNode fast = slow.next;//fast在head.next.next,相当于他们俩开始都从head出发,
        while(slow != fast){
            if(fast == null || fast.next==null)
                return null;
            slow = slow.next;
            fast = fast.next.next;
        }
        return slow;
    }
    public ListNode detectCycle(ListNode head) {
        ListNode node = oneNode(head);
        if(node == null) return null;
        ListNode node1 = head;
        while(node!=node1){
            node = node.next;
            node1 = node1.next;
        }
        return node;

    }
}

你可能感兴趣的:(剑指 Offer II 022. 链表中环的入口节点)