链表中环的入口节点
1、题目
如果个链表中包含环,如何找出环的入口节点?
输入参数:一个链表的头指针pHead
输出结果:链表中环的入口节点,或者是空指针
2、解题
这道题的关键在于链表中环的判断,以及在环存在前提下入口节点的找法
首先,如何判断链表中存在一个环?
定义快慢指针,快指针每次走两步,慢指针每次走一步,若快指针出现走到了链表的末尾nullptr的情况,则说 明链表中不存在环,否则一定会在某个时刻与慢指针重合(可能遍历两次环)。
其次,若链表中有环,如何找到环的入口?
第一步,获取环中的节点数。因为两个指针相遇的节点一定是在环中,则从相遇的这个节点出发,一遍继续向 前移动一遍计数,当再次回到这个节点的时候,即可得到环中节点数目。
第二步,若环中有n个节点,则指针P1先从头节点向前移动n步,然后P2同样从头节点开始,两个指针一起移 动,两个指针相遇的地方即为入口节点。
此外,为什么两个指针相遇的节点一定在环中?
因为快指针走得快,如果链表中有环的话,那么它一定是在环中进行遍历,所以相遇的节点一定在环中
3、代码
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;
//存在环,先获得环所经过的节点数
ListNode* pNode1 = meetingNode;
int nodesInLoop = 1;
while (pNode1->m_pNext != meetingNode) {
pNode1 = pNode1->m_pNext;
++nodesInLoop;
}
pNode1 = pHead;
//快指针先走
for (int i = 0; i < nodesInLoop; i++)
pNode1 = pNode1->m_pNext;
ListNode* pNode2 = pHead;
//快慢一起走
while (pNode1 != pNode2) {
pNode1 = pNode1->m_pNext;
pNode2 = pNode2->m_pNext;
}
return pNode1;
}
4、注意点
- 在判断链表中是否存在环时,先通过慢指针判断链表中是否只有一个节点,若只有一个节点,直接返回空指针
- 快指针前进两步是分别进行的,前进一步后需要进行判空操作,若非空才能再前进一步
- EntryNodeOfLoop调用MeetingNode后,需要对其进行判空操作,在存在环的前提下再继续操作
- 在获取完环的节点数后,记得将pNode1重新指向头节点,再进行走n步的操作