如何确定链表中存在环?
定义两个指针,一个指针一次走一步,一个指针一次走两步,如果走的快的指针追上了走的慢的指针,那么链表中就有环。如果走的快的指针走到了链表的末尾(pnext->nullptr)都没有追上,那么链表中不包含环。
如何找到环的入口?
假设链表中的环有n个节点,那么一个指针先在链表上移动n步,然后两个指针再以相同的速度走,直到两个指针相遇,该位置就是环的入口。第二个指针到了环的入口处,而第一个指针刚好走了一圈。
如何得到环中节点的数目?
如果两个指针相遇说明存在环,相遇的节点一定是在环中,可以从这个节点出发,一边移动一边计数,当再次回到这个节点时,就可以得到环中节点数了。
例:判断是否存在环,存在则找到入口节点。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
//先判断是否包含环
ListNode* pfast=pHead;
ListNode* pslow=pHead;
bool hascycle=false;
ListNode* meetNode=nullptr;
while(pslow->next!=nullptr&&pfast->next->next!=nullptr)
{
pslow=pslow->next;
pfast=pfast->next->next;
if(pslow==pfast)
{
hascycle=true;//存在环
meetNode=pslow;//相遇节点
break;//千万别忘了
}
}
int num=1;
if(hascycle)
{
//找到环中节点数目num
ListNode* pnode=meetNode;
while(pnode->next!=meetNode)
{
pnode=pnode->next;
++num;
}
cout<<num;
ListNode* pslow=pHead;
ListNode* pfast=pHead;
for(int i=0;i<num;i++)
{
pslow=pslow->next;
}
while(pslow!=pfast)
{
pslow=pslow->next;
pfast=pfast->next;
}
return pslow;
}
return nullptr;
}
};
方法二:
找到相遇节点后,可以用一个从起点开始的新指针q和从相遇节点开始的慢指针pslow同步走,相遇的地方必然是入环的第一个节点。
为什么没看太懂。。。先记着吧
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
//先判断是否包含环
ListNode* pfast=pHead;
ListNode* pslow=pHead;
bool hascycle=false;
ListNode* meetNode=nullptr;
while(pslow->next!=nullptr&&pfast->next->next!=nullptr)
{
pslow=pslow->next;
pfast=pfast->next->next;
if(pslow==pfast)
{
hascycle=true;
meetNode=pslow;
break;
}
}
ListNode* q=pHead;
if(hascycle)
{
while(q!=meetNode)
{
q=q->next;
meetNode=meetNode->next;
}
return q;
}
return nullptr;
}
};