题目描述
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
解题思路:
解决这个问题可以分三步。
(1)第一步是确定一个链表中是否包含环。我们可以用两个指针来解决这个问题。定义两个指针,同时从链表的头结点出发,一个指针一次走一步,另一个指针一次走两步。如果走得快的指针追上了走得慢的指针,那么链表就包含环;吐过走得快得快的指针走到了链表的末尾(ListNode的next指向null)都没有追上第一个指针,那么链表就不包含环。
(2)第二步是找到环中节点的数目,这一步的目的就是为寻找环的入口做铺垫。我们在上面提到判断一个链表里面是否有环时用到了一快一慢两个指针。如果两个指针相遇,则表明链表中存在环。两个指针相遇的节点一定是在环中。可以从这个节点出发,一边继续向前移动一边计数,当再次回到这个节点时,就可以得到环中节点数了。
(3)第三步是找到环的入口。我们还可以利用两个指针来解决这个问题。先定义两个指针P1和P2指向链表的头结点。如果链表中的环有n个节点,则指针P1先在链表上向前移动n步,然后两个指针以相同的速度向前移动。当第二个指针指向环的入口节点时,第一个指针已经围绕着环走了一圈,又回到了入口节点。
解题代码:
1.正确代码
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
ListNode* meetingNode=MeetingNode(pHead);
if(meetingNode==nullptr)
return nullptr;
//得到环中节点的数目
int nodesInLoop=1;
ListNode* p1=meetingNode;
while(p1->next!=meetingNode)
{
p1=p1->next;
++nodesInLoop;
}
//找到环的入口
//先移动p1,移动次数为环中节点的个数
p1=pHead;
for(int i=0;i<nodesInLoop;++i)
p1=p1->next;
//再移动p2
ListNode* p2=pHead;
while(p1!=p2)
{
p1=p1->next;
p2=p2->next;
}
return p1;
}
private:
ListNode* MeetingNode(ListNode* pHead)
{
if(pHead==nullptr)
return nullptr;
ListNode* pSlow=pHead->next;
if(pSlow==nullptr)
return nullptr;
ListNode* pFast=pSlow->next;
while(pFast!=nullptr && pSlow!=nullptr)
{
if(pFast==pSlow)
return pSlow;
pSlow=pSlow->next;
pFast=pFast->next;
if(pFast!=nullptr)
pFast=pFast->next;
}
return nullptr;
}
};
2.自己写的没有通过所有用例
您的代码已保存
答案错误:您提交的程序没有通过所有的测试用例
case通过率为75.00%
用例: {},{1,2,3,4,5}
对应输出应该为:1
你的输出为:5
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
if(pHead==nullptr) //空链表
return nullptr;
ListNode* pre=new ListNode(-1);
ListNode* fast=pHead;
ListNode* low=pHead;
pre->next=pHead;
while(fast!=nullptr&&fast->next!=nullptr)
{
pre=pre->next;
low=low->next;
fast=fast->next->next;
if(fast==low)
return pre;
}
return nullptr;
}
};