LeetCode——linked-list-cycle-ii 判断链表是否有环,如果有,返回环的入口
题目描述:
Given a linked list, return the node where the cycle begins. If there is no cycle, returnnull.
Follow up:
Can you solve it without using extra space?
题目分析:
如果可以用额外空间,可以建立map,存放访问节点的地址,如果访问到一个已经访问过的节点,说明有环,返回第一个重复访问节点的地址。
题目要求不要用额外空间,看可以用双指针法。慢指针每次走一步,快指针每次走两步。
具体原理请看灵魂画手精心绘图~
如果没有环,那么快指针将率先到达终点。
如果有环,那么二者终将相遇。
这事,慢指针的走了L+S,快指针比慢指针多走了环周长的n倍(多走了n圈),即 L+S+nR。
而慢指针应为慢指针的2倍,即
(L+S)2=L+S+nR
nR=L+S
L=nR-S
如果一个指针从Begin出发,另一个从Meet处出发,那么终将在入口相遇。
AC代码:
/**
* 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* step_one=head;//都从头结点出发
ListNode* step_two=head;//都从头结点出发
int flag=0;
while(step_one!=step_two||flag==0)//没相遇就一直走(都在起点时不算相遇)
{
flag=1;
step_one=step_one->next;//慢指针走一步
if(step_two!=NULL&&step_two->next!=NULL)
step_two=step_two->next->next;//快指针走两步
else
return NULL;//如果走到头说明没有环
}
ListNode* StartFromBegin=head;//从头结点出发
ListNode* StartFromCross=step_one;//从相遇节点出发
while(StartFromBegin!=StartFromCross)//每次走一步,直达相遇
{
StartFromBegin=StartFromBegin->next;//
StartFromCross=StartFromCross->next;//
}
return StartFromBegin;//相遇节点即为入口
}
};