给定一个单链表,若该链表有环,返回环的起点,若没有,返回NULL
基本思路:
每遇到一个节点,计数器++ ,当遇到访问次数为2时,返回该节点,否则在循环结束前还没有找到,则返回NULL
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
if(!pHead)
return null;
map<ListNode*,int> flag;//统计节点访问次数
while(pHead)
{
if(++flag[pHead]==2)
return pHead;
pHead=pHead->next;
}
return null;
}
};
进阶思路:双指针思路,
- 设置一快一慢双指针,初始化双指针指向起点
- 每次快指针移动2步,慢指针移动1步
- 若有环,则一定在环中相遇
- 设置快指针到起点,2个指针每次移动1步,相遇时即为环起点
证明:
慢指针速度为V 那么快指针速度为2V 第一次相遇,快指针先走了一圈
- Vt=L1+L2
- 2Vt=L1+L2+L3+L2
2式子相减,得出L1=L3 那么将快指针放到起点开始每次移动1步,下次相遇一定发生在环起点位置
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
//链表不存在 或仅仅一个点的情况
if(pHead==NULL || pHead->next==NULL)
return NULL;
//设置双指针(一快 一慢),如果存在环那么一定会在环内相交
ListNode* fast=pHead;
ListNode* slow=pHead;
ListNode* point=NULL;
while(fast->next->next!=NULL && slow->next!=NULL)
{
fast=fast->next->next;//快指针每次走2步
slow=slow->next;//慢指针每次走1步
if(fast==slow) //说明相交了
{
point=fast;
break;
}
}
if(point==NULL)//说明循环结束 还没有相交,也就是没有环
return NULL;
fast=pHead;//将快指针设为头部,速度和slow一致,相遇处即为环起点
while(fast!=slow)
{
fast=fast->next;
slow=slow->next;
}
return fast;
}
};