题目链接
Leetcode.剑指 Offer II 022 链表中环的入口节点 mid
题目描述
给定一个链表,返回链表开始入环的第一个节点。 从链表的头节点开始沿着 next指针进入环的第一个节点为环的入口节点。如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos来表示链表尾连接到链表中的位置(索引从 0开始)。 如果 pos是 -1,则在该链表中没有环。注意,pos仅仅是用于标识环的情况,并不会作为参数传递到函数中。
说明:不允许修改给定的链表。
示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:

输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:

输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。
提示:
- 链表中节点的数目范围在范围 [ 0 , 1 0 4 0, 10^4 0,104] 内
- − 1 0 5 < = N o d e . v a l < = 1 0 5 -10^5 <= Node.val <= 10^5 −105<=Node.val<=105
- pos的值为- -1或者链表中的一个有效索引
分析:快慢指针
我们用两个指针 fast和slow,初始都指向 head,fast每次走两步,slow每次走一步。
如果链表存在环,那么 fast和 slow一定会在环中相遇。

因为fast比slow要快1步,所以当 slow走过的距离为 x + y到达相遇点时,fast其实已经在环里转了若干圈了(这里假设是 n圈)。
所以 fast走过的路程为 ,
    
     
      
       
        x
       
       
        +
       
       
        n
       
       
        ∗
       
       
        (
       
       
        y
       
       
        +
       
       
        z
       
       
        )
       
       
        +
       
       
        y
       
      
      
       x + n * (y + z) + y
      
     
    x+n∗(y+z)+y
又因为 fast走过的路程 应该是 两倍slow走过的路程,即 
    
     
      
       
        x
       
       
        +
       
       
        n
       
       
        ∗
       
       
        (
       
       
        y
       
       
        +
       
       
        z
       
       
        )
       
       
        +
       
       
        y
       
       
        =
       
       
        2
       
       
        ∗
       
       
        (
       
       
        x
       
       
        +
       
       
        y
       
       
        )
       
      
      
       x + n * (y + z) + y = 2 * (x + y)
      
     
    x+n∗(y+z)+y=2∗(x+y)
化简得 : 
    
     
      
       
        x
       
       
        =
       
       
        (
       
       
        n
       
       
        −
       
       
        1
       
       
        )
       
       
        ∗
       
       
        (
       
       
        y
       
       
        +
       
       
        z
       
       
        )
       
       
        +
       
       
        z
       
      
      
       x = (n - 1) * (y + z) + z
      
     
    x=(n−1)∗(y+z)+z,即从相遇点走 z的路程,再走若干圈,就是 x的路程。(我们只需要走 0 圈即可),即 
    
     
      
       
        x
       
       
        =
       
       
        z
       
      
      
       x = z
      
     
    x=z。
当 fast和 slow相遇时,让 fast重新指向头节点 head,fast和slow同时移动,当他们再次相遇时的点,就是环的起点。
时间复杂度: O ( n ) O(n) O(n)
C++代码:
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        if(head == nullptr) return nullptr;
        ListNode *fast = head , *slow = head;
        while(fast && fast->next){
            slow = slow->next;
            fast = fast->next->next;
            //两者相遇
            if(slow == fast){
                fast = head;
                while(slow != fast){
                    slow = slow->next;
                    fast = fast->next;
                }
                return slow;
            }
        }
        return nullptr;
    }
};
Java代码:
/**
 * 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) return null;
        ListNode fast = head;
        ListNode slow = head;
        
        //fast 或 fast.next 为 null , 说明链表没有环
        while(fast != null && fast.next != null){
            slow = slow.next;
            fast = fast.next.next;
            
            //快慢指针相遇了,fast 重新回到头节点 head,快慢指针再同时移动
            if(slow == fast){
                fast = head;
                while(fast != slow){
                    fast = fast.next;
                    slow = slow.next;
                }
                return fast;
            }
        }
        return null;
    }
}



















