给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
● 进阶:你是否可以使用 O(1) 空间解决此题?
解题思路:快慢指针
● 步骤一:判断是否有环,并找到环内节点。
设置一个快指针fast,快指针每次走两个节点。一个慢指针slow,慢指针每次走一个节点。快指针追逐慢指针,直到相遇或者fast==null。此时fast为空说明无环;如果不为空,相遇点一定为环内元素()。
● 步骤二:重置快慢指针,找到环内入口。
slow设置到head的前驱(null),fast设置到相遇点。此时快慢指针每次移动,均只移动一步!直到相遇,此时才是环的入口。该定理推论如图:
推理图及公式
/**
* 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;
// 1、找环中的任意一个点(起点从head前驱,即null开始,这里是已经走了一步了)
ListNode fast = head.next;
ListNode slow = head;
while(fast != null && fast.next != null){
if(fast == slow) break;
fast = fast.next.next;
slow = slow.next;
}
if(fast != slow) return null; // 说明没有环
// 现在找到的点(fast/slow)位于环中
// 2、找环的入口
// 快指针从环内相遇点出发, 慢指针初始化为null(注意!!!),经过一跳到达head
slow = null;
while(slow != fast){
if(slow == null) slow = head;
else slow = slow.next;
fast = fast.next;
}
return fast;
}
}