142. Linked List Cycle II(环形链表2,找到环的入口点)

版权声明:转载请注明 https://blog.csdn.net/qq_34115899/article/details/83240874

Given a linked list, return the node where the cycle begins. If there is no cycle, return null.

Note: Do not modify the linked list.

Follow up:
Can you solve it without using extra space?

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

说明:不允许修改给定的链表。

进阶:
你是否可以不用额外空间解决此题?

/**
 * 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) {
        if (head == null || head.next == null)  return null;
        ListNode runner = head;
        ListNode walker = head;
        while (runner.next != null && runner.next.next != null) {
            walker = walker.next;
            runner = runner.next.next;
            if (walker == runner) {
                ListNode walker2 = head;
                while (walker != walker2) {
                    walker = walker.next;
                    walker2 = walker2.next;
                }
                return walker; // 考虑只有一个结点自环,不能在第二个while里面判断
            }
        }
        return null;
    }
}

原因分析:为什么快慢指针在相遇点时再设置一个指针从头开始慢走,然后第二个指针在环里慢走,再次相遇就是入口点呢?

当它遇到慢速指针walker时,快速指针runner可能会运行几个圆而不是一个圆。

假设快速指针runner运行m个圆圈,并在它们相遇时慢速指针walker运行n个圆圈。然后我们可以得到如下结论:

runner走的距离  =   walker走的距离的几倍,假设是L倍!显然L > 1,因为runner走的一定比walker远

a + m *(b + c)+ b = L * (a + n *(b + c)+ b)

因此我们化简可以得到: m*b + m*c =  (L-1)*a +(L*n+L-1)*b + L*n*c 

有两种可能性:

待定系数法,以b为准

m=L*n+L-1  -------①

m=a/c(L-1) + L*n   -------②

由①②得出

L-1=a/c(L-1)

而L>1,所以a=c成立所以在快慢指针相遇点再设置一个指针从头开始慢走,然后第二个指针在环里慢走,再次相遇就是入口点

待定系数法,以c为准

m=L*n                     -------------①

m=L*n+L-1+a/b(L-1)       ------------②

由①②得出

1-L=a/b(L-1)

L>1,所以a=-b,而距离不可能是负数,所以这种情况不成立!

综上所述,a=c成立

那么,我们只需要在快慢指针相遇点再次设置一个指针从头开始走,在环里的慢指针只走一轮就可以和从头到环的入口点的指针相遇。于是就有了如下部分的代码:

            if (walker == runner) {
                ListNode walker2 = head;
                while (walker != walker2) {
                    walker = walker.next;
                    walker2 = walker2.next;
                }
                return walker; // 考虑只有一个结点自环,不能在第二个while里面判断
            }

=========================Talk is cheap, show me the code========================

猜你喜欢

转载自blog.csdn.net/qq_34115899/article/details/83240874