c++求解链表中环的入口结点

分为三步:

一、判断是否有环:

    两个指针,fast和slow。初始两个指针都指向链表的头结点,fast指针每次前进两步,slow每次前进一步。若链表中有环,两个指针必定会相遇。证明如下:

当链表没有环的时候,fast指针某一时刻为空指针。当链表有环,设k为环的入口结点,环的长度为m,则当slow遍历到结点k时,fast所在的位置为(2k-k)%m=k%m。如果能构计算出两个结点相遇的结点位置,则同时证明了两个结点会相遇。设slow经过x个结点与fast相遇,则有(k%m + 2x)%m = x%m。

k%m+2x-x=ma(其中a>=1,因为当a=0时,表示两个结点在第一环未遍历完的时候就已经相遇,这是不可能的,slow永远在fast的后面)

x=ma-k%m=ma-(k-mb)=m(a+b)-k>=0,其中,b>=0,m>=k(m>=k的含义是两个结点相遇的位置总是在环中)。得证。

二、求环的长度:

    在判断是否有环的过程中记录两个结点相遇的位置p,从结点p开始遍历链表,当当前结点再次指向结点p时,当前节点走完了一环。此时,也就知道了环的长度len。

三、求环的入口结点:

    两个指针,fast和slow。初始均指向链表的头结点,fast先走len个位置,此时slow也开始走。当fast->next == slow时,表明找到了环的入口结点slow。

代码如下:

#include <iostream>

using namespace std;

struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
	val(x), next(NULL) {
	}
};

class Solution {
public:
	ListNode* EntryNodeOfLoop(ListNode* pHead)
	{
		if (!pHead)	return nullptr;
		int len = 0, count = 0;
		ListNode* result;
		ListNode* ppre = pHead;
		ListNode* pcur = pHead;
		ListNode* temp;
		if (isloop(temp, pHead)) {
			len = Looplength(temp);
			while (++count < len) {
				ppre = ppre->next;
			}
			while (ppre->next != pcur) {
				ppre = ppre->next;
				pcur = pcur->next;
			}
			result = pcur;
			return result;
		}
		return nullptr;
	}

	bool isloop(ListNode* &temp, ListNode* pHead) {
		ListNode* ppre;
		ListNode* pcur;
		if (pHead->next) {
			ppre = pHead->next->next;
			pcur = pHead->next;
		}
		else
		{
			return false;
		}
		bool result = false;
		while (ppre && pcur) {
			if (ppre == pcur) {
				temp = pcur;
				result = true;
				break;
			}
			if (ppre->next) {
				ppre = ppre->next->next;
			}
			pcur = pcur->next;
		}
		return result;
	}
	int Looplength(ListNode* pcur) {
		int length = 0;
		const ListNode* p = pcur;
		while (pcur->next != p) {
			length++;
			pcur = pcur->next;
		}
		length++;
		return length;
	}
};

int main() {
	ListNode* pHead = new ListNode(1);
	ListNode* p1 = new ListNode(2);
	ListNode* p2 = new ListNode(3);
	ListNode* p3 = new ListNode(4);
	pHead->next = p1;
	p1->next = p2;
	p2->next = p3;
	p3->next = p1;
	Solution s;
	ListNode* result = s.EntryNodeOfLoop(pHead);
	cout << result->val;
	system("pause");
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值