单链表关于环的几个问题

问题:

1.单链表是否有环

2.环的节点长度

3.环的入口节点

4.表头到环入口的节点长度

问题1.思路:

在表头设置fast、slow指针,fast一次遍历两个节点,slow一次遍历一个节点,若相遇则证明有环,反之则不存在环

代码:

/**
 *引入快慢指针,若指针相遇则证明链表有环
 */
Node * findRing(Node *head) 
{
	Node * fast = head, *slow = head;
	while (fast&&fast->next) {
		fast = fast->next->next;
		slow = slow->next;
		if (slow == fast)
			return slow;
	}
	return NULL;
}

问题2.思路:从fast、slow指针相遇开始,再次出发,再次相遇时slow走过的距离即为环的长度

代码:

/**
 *meetPoint为快慢指针相遇的节点指针
 *快慢节点再次相遇的时候,慢指针走过的长度即为环的长度
 */
int ringLen(Node * meetPoint) {
	Node *fast = meetPoint;
	Node *slow = meetPoint;
	int ringLen = 0;
	while (true) {
		fast = fast->next->next;
		slow = slow->next;
		ringLen++;
		if (fast == slow)
			break;
	}
	return ringLen;
}

ps:可以直接让slow重相遇点出发,重新到达相遇点时,即为环的长度

问题3.思路

设指针p指向链表表头,q指向slow、和fast的相遇节点,两个指针同时开始遍历,当两个节点相遇时,相遇节点为环入口节点

代码:

Node * ringEntr(Node * head , Node * meetPoint) {
	Node * p = head, *q = meetPoint;
	while (p != q) {
		p = p->next;
		q = q->next;
	}
	return p; 
}

https://blog.csdn.net/u011373710/article/details/54024366

上面这篇博客对问题三有比较详细的证明

这里再解释一下(思路都是由上面的博客得来的):

1.刚开始h、fast、slow在表头,环的入口为t,fast开始一步两个节点遍历链表,slow开始以一步一个节点遍历链表,h指针不动

2.当slow到达入口t时,设fast在m1,从t到m1的逆时针距离为b,环的长度为r,从m1到t的距离为r-b,同理从fast到slow的距离为也为r-b

3.这时fast可能已经绕了n圈,所以表头到t的距离a = nr +b

4.设m2为在slow、fast的相遇节点,slow和fast之间的速度差为1,距离差为r-b,时间(r-b)/1 = r-b,slow走过的路径为(r-b)*1=r-b,所以m2到t的距离为b,h这时从表头出发,slow继续遍历

5.h从表头出发走过距离为b时,slow到达t点,由3可得 a =  nr + b 这时 a - b = nr h到t剩下的距离是环长度的整数倍,故当后到达t时必然与slow相遇

问题4.思路:

在问题3的基础上,从h出发时加上一个计数器,当h和slow相遇时既可以的到表头到环入口的距离

int getLenA(Node * head,Node * meetPoint) {
	Node * p = head,*q = meetPoint;
	int len = 0;
	while (p != q) {
		p = p->next;
		q = q->next;
		len++;
	}
	return len;
}

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值