时间限制:1秒 空间限制:32768K 热度指数:239075
本题知识点: 链表
题目描述
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
解题思路:
可以用两个指针来解决这个问题。先定义两个指针P1和P2指向链表的头结点。如果链表中的环有n个结点,指针P1先在链表上向前移动n步,然后两个指针以相同的速度向前移动。当第二个指针指向的入口结点时,第一个指针已经围绕着揍了一圈又回到了入口结点。
以下图为例,指针P1和P2在初始化时都指向链表的头结点。由于环中有4个结点,指针P1先在链表上向前移动4步。接下来两个指针以相同的速度在链表上向前移动,直到它们相遇。它们相遇的结点正好是环的入口结点。
现在,关键问题在于怎么知道环中有几个结点呢?
可以使用快慢指针,一个每次走一步,一个每次走两步。如果两个指针相遇,表明链表中存在环,并且两个指针相遇的结点一定在环中。
随后,我们就从相遇的这个环中结点出发,一边继续向前移动一边计数,当再次回到这个结点时,就可以得到环中结点数目了。
代码如下:
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
if(pHead==NULL) return NULL;
ListNode *c=node(pHead);//相遇的结点
if(c==NULL) return NULL;
//链表中的结点的个数
int cnt=1;
ListNode *circle=c;
while(circle->next!=c){
cnt++;
circle=circle->next;
}
ListNode *pHead1=pHead,*pHead2=pHead;
//pHead1向前移动cnt步
for(int i=0;i<cnt;i++){
pHead1=pHead1->next;
}
//两个指针同时移动,找到环的入口
while(pHead1!=pHead2){
pHead1=pHead1->next;
pHead2=pHead2->next;
}
return pHead1;
}
private:
//使用快慢指针,找到任意的一个环中结点
ListNode *node(ListNode *pHead){
ListNode *a=pHead->next;
if(a==NULL) return NULL;
ListNode *b=a->next;//a为慢指针,b为快指针
while(b!=NULL&&a!=NULL){
if(b==a){
return b;
}
a=a->next;
b=b->next;
if(b!=NULL){
b=b->next;
}
}
return NULL;
}
};