102.带环链表
转自带环链表得几个问题
判断一个链表是否有环,如果有环,则返回入环的第一个节点,否则返回null
如果一个链表有环,遍历一个链表便永远不会到达null,否则必定会到达null。设置两个指针,刚开始都指向头节点,遍历时,一个指针每次前进一步,我们称之为慢指针,另一个每次前进两步,称之为快指针,这样,如果链表没有环,快指针必然会到达null,如果有环,两个指针必然会相交于一点。
下面再来看看如何找到入环的第一个节点,假设从头节点到入环第一个节点的长度为m,两个指针第一次相遇时的节点距离环入口点的长度为t,环的长度为n,那么此时慢指针走的长度为m+t,快指针走的长度为m+t+kn(k=0,1,2...),kn项表示快指针有可能在环内走了几圈后再与慢指针相遇,这时满足
m+t+kn = 2(m+t)
简化得到
m = (k-1)n + n - t
其中n-t项正表示了慢指针走完当前环还需要走的长度,从这里就可以看出此时如果将快指针放回头节点,然后让它每次只走一步,那么这两个指针必然会相交,并且相交的交点就是入环点。
/**
* Definition of ListNode
* class ListNode {
* public:
* int val;
* ListNode *next;
* ListNode(int val) {
* this->val = val;
* this->next = NULL;
* }
* }
*/
class Solution {
public:
/**
* @param head: The first node of linked list.
* @return: the node where the cycle begins.
* If there is no cycle, return null
*/
ListNode *detectCycle(ListNode *head) {
// write your code here
ListNode* ptr1,* ptr2;
if(head == NULL)
return NULL;
ptr1 = head ;
ptr2 = head;
while(ptr2->next != NULL && ptr2->next->next != NULL)
{
ptr1 = ptr1->next;
ptr2 = ptr2->next->next;
if(ptr1 == ptr2)
{
ptr1 = head;
while(ptr1 != ptr2)
{
ptr2 = ptr2->next;
ptr1 = ptr1->next;
}
return ptr1;
}
}
return NULL;
}
};