成环问题一---判断链表是否成环
链表成环,即尾结点的next指针不再指向空NULL,而是指向了该链表中的某一个结点而从该结点处形成了一个环。
那么对于成环链表而言,我们使用快慢指针fast与slow,两者每次差一步,那么若链表成环,fast指针会走到slow的后面,然后反过来追到slow,那么当fast能够追到slow,那就说明该链表成环,循环条件依旧是fast和fast->next不为NULL,如果不成环就能够跳出循环返回false。
那么判断是否成环就很简单了,代码如下:
bool hasCycle(struct ListNode *head) {
struct ListNode* slow ,*fast;
fast = slow = head;
while(fast&&fast->next)
{
fast=fast->next->next;
slow=slow->next;
if(fast == slow)
return true;
}
return false;
}
成环问题二---成环请返回入环结点
思路一:相遇点与头结点遍历得到入环节点
通过问题一,我们知道成环的判断方法,那么现在主要的问题就是入环点的求解,我们其实能够知道fast与slow的相遇结点。 那么我们假设头结点到入环点的距离为L,环的长度为C,fast与slow相遇点与入环点距离为X。 我们来看成环的情况,画出图:
那么通过上面的图,fast走了---L+n*C+X ;slow走了L+X。
我们又知道fast走的距离是slow的两倍,因此就能够创造一个等式---L+n*C+X = 2*(L+X)。
化简---L = n*C - X。
这个式子很有意义,放在图里有什么意义呢?L是起点到入环点的距离,n*C-X等价于(n-1)*C+C-X是相遇点在环里跑了n-1圈然后跑到环入口点的路程。L与n*C-X相等,说明同速的相遇点指针与头结点指针一起走,那么就会同时到环入口点,那么就能够判断了。
那么就很简单了,找到相遇点rhead,然后从相遇点rhead开始和头结点head开始,同时遍历直道两者相等返回其中任意一个指针即可。
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode* slow ,*fast;
fast = slow = head;
while(fast&&fast->next)
{
fast = fast->next->next;
slow=slow->next;
if(slow == fast)
{
struct ListNode* rhead = slow;
while(rhead != head)
{
rhead =rhead->next;
head = head->next;
}
return rhead;
}
}
return NULL;
}
还有一个问题:环的入环点一定是尾结点吗?
不一定!当尾结点的next指针指向自己时,入环点才是尾结点,否则,指向哪个结点,入环点就是哪个结点。
思路二:断开相遇点,转换为链表相交问题
如果我们没有想到上述方法,我们也可以换一种思路:转换为链表相交问题
代码如下:
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode* slow ,*fast;
fast = slow = head;
while(fast&&fast->next)
{
fast = fast->next->next;
slow=slow->next;
if(slow == fast)
{
//转换为链表相交问题
struct ListNode* rhead = slow->next;
slow->next =NULL;
struct ListNode* cur = head;
struct ListNode* rcur = rhead;
int A = 0;
int B = 0;
while(cur)
{
cur=cur->next;
A++;
}
while(rcur)
{
rcur=rcur->next;
B++;
}
int n =abs(A-B);
struct ListNode* Longlist = head;
struct ListNode* Shortlist = rhead;
if(A<B)
{
Longlist = rhead;
Shortlist = head;
}
while(n--)
{
Longlist=Longlist->next;
}
while(Longlist!=Shortlist)
{
Longlist = Longlist->next;
Shortlist = Shortlist->next;
}
return Longlist;
}
}
return NULL;
}