题目:44. 链表中环的入口结点
知识点:链表
题目描述:
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
解题思路:
解题的思路比较简单,使用两个快慢两个指针,快指针一次走两步,慢指针一次走一步,根据数学知识可得,当链表中存在环的时候,在环中快指针一定可以再领先慢指针一圈后与慢指针相遇,根据这个原理可以直接判断链表中是否存在环,第二步是当链表存在环的时候,我们需要求得环的入口结点,根据公式可得,只需先在第一步中求得环的长度(快指针减去慢指针的步数,即慢指针的步数),相同的还是使用两个指针,一个指针先走环长的步数,然后两个指针同时前移,这时当两个指针相遇的时候,刚好是环的入口结点。
代码:
//解法一(自研):
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
if(pHead == nullptr || pHead->next == nullptr)
return nullptr;
ListNode* p1 = pHead;
ListNode* p2 = pHead;
int num = 0;
do {
p1 = p1->next;
p2 = p2->next->next;
num++;
} while(p2 != nullptr && p2->next != nullptr && p1 != p2);
if(p2 == nullptr || p2->next == nullptr)
return nullptr;
p1 = pHead; p2 = pHead;
while(num-- > 0)
p2 = p2->next;
while(p1 != p2){
p1 = p1->next;
p2 = p2->next;
}
return p1;
}
//解法二(剑指Offer 解题思路同上):
ListNode* MeetingNode(ListNode* pHead)
{
if(pHead == nullptr)
return nullptr;
ListNode* pSlow = pHead->m_pNext;
if(pSlow == nullptr)
return nullptr;
ListNode* pFast = pSlow->m_pNext;
while(pFast != nullptr && pSlow != nullptr)
{
if(pFast == pSlow)
return pFast;
pSlow = pSlow->m_pNext;
pFast = pFast->m_pNext;
if(pFast != nullptr)
pFast = pFast->m_pNext;
}
return nullptr;
}
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
ListNode* meetingNode = MeetingNode(pHead);
if(meetingNode == nullptr)
return nullptr;
// 得到环中结点的数目
int nodesInLoop = 1;
ListNode* pNode1 = meetingNode;
while(pNode1->m_pNext != meetingNode)
{
pNode1 = pNode1->m_pNext;
++nodesInLoop;
}
// 先移动pNode1,次数为环中结点的数目
pNode1 = pHead;
for(int i = 0; i < nodesInLoop; ++i)
pNode1 = pNode1->m_pNext;
// 再移动pNode1和pNode2
ListNode* pNode2 = pHead;
while(pNode1 != pNode2)
{
pNode1 = pNode1->m_pNext;
pNode2 = pNode2->m_pNext;
}
return pNode1;
}