环形链表:环是否存在?环的入口
leetcode题目:142,给定一个头节点,判断该链表中是否存在环,如果存在返回环的入口节点,否则返回NULL。
1 判断链表中是否存在环
难点:如果有环存在,则单个指针的遍历会一直进行下去,无循环的出口;除非知道环中的某一个节点,这样遍历才可以有终止条件
解决办法:快慢指针法:快指针每次走两步,慢指针每次走一步,如果有环存在,则快指针和慢指针将会再环中相遇
ListNode *slow, *fast;
if(head && head -> next && head -> next -> next)
{
slow = head -> next;
fast = head -> next -> next;
}
else return NULL;
while(slow != fast)
{
if(fast -> next && fast -> next -> next)
fast = fast -> next -> next
slow = slow -> next;
}
2. 寻找环的入口
由于slow走一步的时候,fast走两步,即slow经过一个节点时,fast经过两个节点
所以:2*(k+i-1) = k+i-1+x(n-k),
当 x = 1时,k + i - 1 = n - k , 所以, k = n - k - i +1
k = n - k - i + 1 所以如果两个指针分别从 头节点、相遇节点出发,从头节点出发的指针经过k 个节点后将到达 入口节点,从相遇节点出发的节点经过同样的节点个数后也到达入口节点
所以设置index1, index2,分别从头节点和相遇节点出发,经过若干节点后两节点指向了同一节点,则指向的节点为环入口。
ListNode *index1 = head, *index2 = slow;
while(index1 != index2)
{
index1 = index1 -> next;
index2 = index2 -> next;
}
return index1;
完整程序
/**
* 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, *slow;
if(head && head -> next && head ->next -> next)
{
slow = head -> next;
fast = head -> next -> next;
}
else return NULL;
while(slow != fast)
{
if(fast -> next && fast -> next -> next)
{
slow = slow -> next;
fast = fast -> next -> next;
}
else return NULL;
}
//寻找环的入口节点
ListNode *index1 = head, *index2 = slow;
while(index1 != index2)
{
index1 = index1 -> next;
index2 = index2 -> next;
}
return index1;
}
};
index2 = index2 -> next;
}
return index1;
}
};