剑指offer------链表中环的入口结点

题目

一个链表中包含环,请找出该链表的环的入口结点。

思路

可以用两个指针来解决这个问题。先定义两个指针P1和P2指向链表的头结点。如果链表中的环有n个结点,指针P1先在链表上向前移动n步,然后两个指针以相同的速度向前移动。当第二个指针指向的入口结点时,第一个指针已经围绕着揍了一圈又回到了入口结点。

以下图为例,指针P1和P2在初始化时都指向链表的头结点。由于环中有4个结点,指针P1先在链表上向前移动4步。接下来两个指针以相同的速度在链表上向前移动,直到它们相遇。它们相遇的结点正好是环的入口结点。

剑指Offer(五十五):链表中环的入口结点

现在,关键问题在于怎么知道环中有几个结点呢?

可以使用快慢指针,一个每次走一步,一个每次走两步。如果两个指针相遇,表明链表中存在环,并且两个指针相遇的结点一定在环中。

随后,我们就从相遇的这个环中结点出发,一边继续向前移动一边计数,当再次回到这个结点时,就可以得到环中结点数目了。

第三部,让头指针移动计数的次数phead2,让后同时让头指针和phead2移动,相遇的地方就是入口。

程序:

/*
struct Listnode
{
	int value;
	struct Listnode *next
}
*/

class Solution
{
public:
	Listnode* EntyNodeOfLoop(Listnode* pHead)
	{
		if(pHead==NULL)
			return NULL;
		
		Listnode* meetingnode = MeetingNode(pHead);
		if(meetingnode ==NULL)
			return NULL;
		
		//环的结点个数
		int nodesloop= 1;
		Listnode* pNode1=meetingnode;
		while(pNode1->next!=meetingnode)
		{
			pNode1=pNode1->next;
			nodesloop++;
		}
		
		pNode1 = pHead;
		//第一个指针移动nodesloop步
		for(int i=0;i<nodesloop;i++)
		{
			pNode1  = pNode1->next;
		}
		
		//两个指针同时移动,相遇找到环的入口
		Listnode* pNode2 = pHead;
		while(pNode1!=pNode2)
		{
			pNode1 = pNode1->next;
			pNode2 = pNode2->next;
		}
		return pNode1;
	}
	
private:
	//使用快慢指针,找到任意的一个环中结点
	Listnode* MeetingNode(Listnode* pHead)
	{
	Listnode* pSlow = pHead->next;
	if(pSlow==NULL)
		return NULL;
		
	Listnode* pFast = pSlow->next;
	while(pFast!=NULL && pSlow!=NULL)
	{
		if(pFast==pSlow)
			return pFast;
		
		//移动一步
		pSlow=pSlow->next;
		
		//移动两步
		pFast=pFast->next;
		if(pFast!=NULL)
			pFast = pFast->next;
		
	}
	
	return NULL;
	
	}
};
		

参考资料《剑指offer》

猜你喜欢

转载自blog.csdn.net/qq_39503189/article/details/82190504