链表-环形链表II

76 阅读2分钟

环形链表II

描述

给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。不允许修改 链表。

分析

首先判断是否存在环的题目,对应leetcode的141. 环形链表,解法是用快慢指针,这个很简单。此题的关键在于需要在发现了环之后,再去寻找环的入口。

  1. 首先,当快慢指针相遇的时候 ,设fast的路程 fd=a+k1 * x ; slow的路程 sd =a+k2 * x。(其中a代表进入环前的路程数,x代表一个环的路程数)
  2. 由于快指针每次走两步,慢指针每次走一步,所以快指针走过的路程是慢指针的两倍。fd=2 * sd 。简化等式可以得到 a= (k1-k2) * x。由于k1-k2>0 ,简化为 a=k * x ,(k>0)。
  3. 所以fd =n1 * x, sd =n2 * x ,(n1,n2>0)。 这是他们相遇时走的路程数量。我们发现只要slow或fast再走a步就能重新到达环的入口。
  4. 所以,我们让fast走到起点,slow和fast同步走,当他们相遇后,那个位置就是环的入口。

代码


    public ListNode detectCycle(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;

        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if (fast == slow) {
                fast = head;
                while (true) {
                    if (fast == slow) {
                        return slow;
                    }
                    fast = fast.next;
                    slow = slow.next;
                }
            }
        }
        return null;
    }