初阶。
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.
}
}