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

题目:如果一个链表中包含环,如何找出环的入口节点?如下图所示,环的入口节点是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;



}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值