题目:
如果一个链表中包含环,请找出该链表的环的入口结点。
例子
如:在1->2->3->4->5->6->3的链表中,包含一个环,环的入口节点是3。
链接:
剑指Offer(第2版):P139
思路标签:
- 数据结构:链表
- 算法:双指针
解答:
1. C++
- 对问题进行分步解决。
- (1) 确定链表中是否包含环:双指针,一个每次移动一步,一个每次移动两步,如果两个指针最后相遇,那么就包含环。(注意,移动两步的指针要判断判断其第一步不为空,才能移动第二步)
- (2) 确定环中点节点数目:在上面相遇的节点的基础上,移动一个指针,并计数,当指针回到该节点时,确定环中节点数目。
- (3) 找到环的入口节点:从头开始,使用两个指针,第一个指针先移动n步(其中n为确定的环中的节点数目),第二个指针再开始同时移动,两个指针相遇的节点即为入口节点。
/*
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 nodesNumInLoop = 1;
ListNode* pNode1 = meetingNode;
while(pNode1->next != meetingNode){
pNode1 = pNode1->next;
++nodesNumInLoop;
}
pNode1 = pHead;
for(int i=0; i<nodesNumInLoop; ++i)
pNode1 = pNode1->next;
ListNode* pNode2 = pHead;
while(pNode1 != pNode2){
pNode1 = pNode1->next;
pNode2 = pNode2->next;
}
return pNode1;
}
ListNode* MeetingNode(ListNode* pHead){
if(pHead == nullptr) return nullptr;
ListNode* pSlow = pHead->next;
if(pSlow == nullptr) return nullptr;
ListNode* pFast = pSlow->next;
while(pSlow != nullptr && pFast != nullptr){
if(pSlow == pFast) return pFast;
pSlow = pSlow->next;
pFast = pFast->next;
if(pFast != nullptr)
pFast = pFast->next;
}
return nullptr;
}
};