Linked List Cycle

初阶。

Given a linked list, determine if it has a cycle in it.
Follow up: Can you solve it without using extra space?



进阶。

Given a linked list, return the node where the cycle begins. If there is no cycle, return null.
Follow up: Can you solve it without using extra space?


关于这类问题:

1)有没有环。快慢指针,快指针一次走两步,慢指针一次走一步,如果相遇则有环。

2)环的入口节点。

快慢指针第一次相遇,慢指针肯定没走完一圈。为什么?

假设慢指针速度是V,快指针是2V,慢指针进入时距离快指针a。那么快指针相对慢指针的速度是v,第一次相遇的距离是r(环长) - a;时间t=(r-a)/v。慢指针走动的距离也就是vt=r-a。肯定不到一圈啦。


链长L,表头到环入口为a,换入口到相遇点x,环长r。慢指针s,快指针2s。

在链表头和相遇点分别设置一个指针,每走一步,两个指针必定在环入口点相遇。从链表头出发的指针指向的就是入口节点。

2s=s+nr;

s=nr;

a+x=nr;

a+x=(n-r)+r=(n-1)r+L-a

a=(n-1)r+(L-a-x)

(L – a – x)为相遇点到环入口点的距离,由此可知,从链表头到环入口点等于(n-1)循环内环+相遇点到环入口点,于是我们从链表头、与相遇点分别设一个指针,每次各走一步,两个指针必定相遇,且相遇第一点为环入口点.

3)环的长度

在快慢指针相遇后,定住一个指针,另外一个指针每次走一步,下次相遇时就是环的长度.

#include <iostream>
using namespace std;

struct LinkNode{
	int data;
	LinkNode *next;
	LinkNode(int x):data(x),next(NULL){}
};

class Solution{
public:
	//判断是否有环
	bool hasCycle(LinkNode *head)
	{
		//快慢指针
		LinkNode *fast=head,*slow=head;
		while(fast && fast->next)
		{
			slow = slow->next;
			fast = fast->next->next;
			if(slow==fast) return true;
		}
		return false;
	}

	//计算环的入口点
	//在链表头和相遇点分别设置一个指针,每走一步,两个指针必定在环入口点相遇。
	LinkNode *findLoopPort(LinkNode *head)
	{
		LinkNode *fast=head,*slow=head;
		while(fast && fast->next)
		{
			slow = slow->next;
			fast = fast->next->next;
			if(slow==fast)
			{
				LinkNode *slow2 = head;
				while(slow!=slow2)
				{
					slow = slow->next;
					slow2 = slow2->next;
				}
				return slow2;
			}
		}
		return NULL;
	}

	//计算环的长度
	//在快慢指针相遇后,定住一个指针,另外一个指针每次走一步,下次相遇时就是环的长度。
	int getLoopLen(LinkNode *head)
	{
		int len=0;
		LinkNode *slow=head,*fast=head;
		while(fast && fast->next)
		{
			slow=slow->next;
			fast=fast->next->next;
			if(slow == fast)//肯定有环
			{
				//固定slow,fast一次走一步,下一次相遇走的距离就是环的长度。
				fast = fast->next;
				while(fast!=slow)//这里用do while更好,先运算在判断。
				{
					fast=fast->next;
					len++;
				}
				len = len + 1;
				return len;
			}
		}
		return 0;//没有环,return 0.
	}
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值