题目:如果一个链表中包含环,如何找出环的入口节点?如下图所示,环的入口节点是3
思路:
这道题的思路还是很巧妙的, 首先要去判断链表里面有没有环的存在。这里定义两个指针,同时从链表的头节点出发,一个指针一次走一步,一个指针一次走两步。如果走的块的指针追上了走的慢的指针,那么链表就包含环;如果走的块的指针走到了链表的末尾(m_pNext指向NULL)都没有追上第一个指针,那么链表就不包含环。
第二步,是在有环的前提下去找环的起点,如果知道链表节点的数目(假设是n),那么还是设两个指针都指向头节点,一个指针先走n步,之后两个指针同时再走,这样当后走的指针走到环的入口节点的时候,先走的指针刚好走完了环的一圈回到入口节点。那么又怎么知道环里面节点的数目呢?还是由刚才的第一步得到两个指针的交点,这个交点必然是处于环内的,那么我们让一个指针从这个交点出发,不断地将指针向后移动,同时将节点数目加一,直到这个指针回到这个交点,那么我们就统计出了环内的节点数目。这道题的思路太有意思了,好好记一下。
代码:
struct ListNode
{
int m_nValue;
ListNode* m_pNext;
};
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 nodeInLoop = 1;
ListNode* pNode1 = meetingNode;
while (pNode1->m_pNext!=meetingNode)
{
pNode1 = pNode1->m_pNext;;
++nodeInLoop;
}
//先移动pNode1,次数为环中节点的数目
pNode1 = pHead;
for (int i = 0; i < nodeInLoop; ++i)
pNode1 = pNode1->m_pNext;
//再移动pNode1和pNode2
ListNode*pNode2 = pHead;
while (pNode1!=pNode2)
{
pNode1 = pNode1->m_pNext;
pNode2 = pNode2->m_pNext;
}
return pNode1;
}
复习:
有意思的题目,要注意pSlow和pFast定义以及赋值的时候要时刻判断是指针否为空,逻辑要清晰。
二刷代码:
struct ListNode
{
int m_value;
ListNode* m_pNext;
};
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 (pSlow != nullptr&&pFast != nullptr)
{
if (pSlow == pFast)
return pFast;
pSlow = pSlow->m_pNext;
pFast = pFast->m_pNext;
if (pFast->m_pNext != nullptr)
pFast = pFast->m_pNext;
}
return nullptr;
}
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
ListNode* meetingNode = MeetingNode(pHead);
if (meetingNode == nullptr)
return nullptr;
ListNode* pNode1 = meetingNode;
int nodeLoop = 1;
while (pNode1->m_pNext!=meetingNode)
{
pNode1 = pNode1->m_pNext;
++nodeLoop;
}
pNode1 = pHead;
for (int i = 0; i < nodeLoop; i++)
{
pNode1 = pNode1->m_pNext;
}
ListNode* pNode2 = pHead;
while (pNode1!=pNode2)
{
pNode1 = pNode1->m_pNext;
pNode2 = pNode2->m_pNext;
}
return pNode1;
}