剑指offer之面试题23:链表中环的入口节点

链表中环的入口节点

1、题目

如果个链表中包含环,如何找出环的入口节点?

输入参数:一个链表的头指针pHead

输出结果:链表中环的入口节点,或者是空指针

2、解题

这道题的关键在于链表中环的判断,以及在环存在前提下入口节点的找法

首先,如何判断链表中存在一个环?

​ 定义快慢指针,快指针每次走两步,慢指针每次走一步,若快指针出现走到了链表的末尾nullptr的情况,则说 明链表中不存在环,否则一定会在某个时刻与慢指针重合(可能遍历两次环)。

其次,若链表中有环,如何找到环的入口?

​ 第一步,获取环中的节点数。因为两个指针相遇的节点一定是在环中,则从相遇的这个节点出发,一遍继续向 前移动一遍计数,当再次回到这个节点的时候,即可得到环中节点数目。

​ 第二步,若环中有n个节点,则指针P1先从头节点向前移动n步,然后P2同样从头节点开始,两个指针一起移 动,两个指针相遇的地方即为入口节点。

此外,为什么两个指针相遇的节点一定在环中?

​ 因为快指针走得快,如果链表中有环的话,那么它一定是在环中进行遍历,所以相遇的节点一定在环中

剑指offer之面试题23:链表中环的入口节点_第1张图片

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步的操作

你可能感兴趣的:(剑指offer,指针,链表,单链表,数据结构,算法)