题
面试题 02.08. 环路检测
给定一个链表,如果它是有环链表,实现一个算法返回环路的开头节点。若环不存在,请返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:tail connects to node index 1
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:tail connects to node index 0
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:no cycle
解释:链表中没有环。
进阶:
你是否可以不用额外空间解决此题?
题解
-
利用快慢指针判断有没有环
-
如果有,则快慢指针会在某点相遇,因为快指针多跑了,但相遇的点不一定是环的入口。
-
不妨设链表的头节点到环的入口节点的距离为s1,入口节点到二者相遇点的距离为s2 我们得到这样一个各自所跑的距离
-
快指针移动的距离是y1=( s1+s2+xn)快指针先从头节点跑到相遇节点,然后在环里不断的跑,n为次数,x为跑的圈数,直到遇到慢指针
-
慢指针移动的距离是y2=(s1+s2)慢指针从头节点跑到二者相遇的阶段
-
二者存在一个潜在的等量关系,y1=2y2,即是(s1+s2+xn)=2(s1+s2)
-
整理一下s1+s2=xn
-
进一步整理:s1=(n-s2)+(x-1)n
-
由s1+s2=xn知道快指针移动s1步,到达入口,慢指针也移动s1步,换算成上面这个等式,(x-1)n等于绕圈,没动,实际移动了(n-s2),也到达了入口。
-
然后从头结点和相遇节点开始同时步长为1遍历 当两个相同时 必定移动了s1步此时返回指针所指位置,就是入口。
代码
/**
* 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) {
ListNode *fast = head, *slow = head;
while (slow&&fast&&fast->next)
{
slow = slow->next;
fast = fast->next->next;
if (fast == slow)
{
while (head != fast) {
head = head->next;
fast = fast->next;
}
return head;
}
}
return NULL;
}
};