一.判断链表是否有环
1.用快慢指针来解决,定两个slow,fast两个指针分别指向head
2.slow一次走一步,fast一次走两步,slow进环之后开始追击问题,如果相遇就带环。
struct ListNode* fast=head,* slow=head;
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if(slow == fast)
return true;
}
return false;
这里有几个小问题:
(1).为什么会相遇,有没有可能错过,永远都追不上,请证明
假设slow和fast两个指针在如图所在的位置,并设其之间的距离为N,进行追击距离会从N,N-1,N-2......3,2,1,0,逐渐减小为0,最后相遇。
(2).slow走一步,fast走n步(n>=3)可能相遇吗,请证明
假设fast一次走3步,slow,fast指针如图所示,设其之间的距离为N。
slow走一步,fast走三步
所以其中的距离,假如N为偶数,那么距离变化为N,N-2,N-4......4,2,0;如果N为奇数,那么距离变化为N,N-2,N-4......3,1,-1。
如果错过,距离为-1,则开始新一轮的追击,设环形周长为C,所以距离变成了C-1。
这里也分两种情况。
若C-1为偶数即沿用N是偶数的情况,最后距离会变成0,相遇。
若C-1为奇数,那就永远都追不上。
通过以上的案例你可以发现,追击问题中,速度差是关键!
例如,slow走1步,fast走4步,速度差是3
假设进环的距离为N。N%3==0,N%3==1,N%3==2,分别是三种状况。
又从以上案例你会发现,当N是奇数,C是偶数,则永远都追不上。
假设slow进环时,fast跟slow距离是N
slow走的距离是:L
fast走的距离是:L+x*C
slow进环时,假设fast已经在环里转了x圈
所以当fast走的距离是slow的3倍时,有关系式:
3*L=L+x*C+C-N
化简得:2*L=(x+1)*C-N,
假如N为奇数,即偶数=(x+1)*偶数-奇数,等式不成立,只有奇数-奇数才能等于偶数。反证出N是奇数,C是偶数,则永远都追不上。
结论:一定能追上,N是偶数第一轮就追上了;N是奇数第一轮追不上,C-1是偶数第二轮就追上了。
二.寻找环的入口点
struct ListNode *detectCycle(struct ListNode *head)
{
struct ListNode* fast=haed, *slow=head;
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
//相遇
if(slow == fast)
{
struct ListNode* meet = slow;
while(meet != head)
{
meet=meet->next;
head =head->next;
}
return meet;
}
}
return NULL;
}
相遇时:
slow走过的路程:L+N
fast走过的路程:L+x*C+N
fast走的路程是slow的2倍
2*(L+N)=L+x*C+N
化简可得:L=x*C-N
即L=(x-1)*C+C-N
图中绿色的部分相等。
还有另一种解法,将问题转变成链表的相交。
struct ListNode* getIntersectionNode(struct ListNode* headA, struct ListNode* headB)
{
if(headA==NULL && headB==NULL)
{
return NULL;
}
struct ListNode* curA = headA, * curB = headB;
int count1 = 0, count2 = 0;
while (curA->next != NULL)
{
count1++;
curA = curA->next;
}
while (curB->next != NULL)
{
count2++;
curB = curB->next;
}
int gap = abs(count1 - count2);
struct ListNode* longlist = headA;
struct ListNode* shortlist = headB;
if (count1 < count2)
{
longlist = headB;
shortlist = headA;
}
if (curB == curA)
{
while (gap--)
{
longlist = longlist->next;
}
while (longlist != shortlist)
{
longlist = longlist->next;
shortlist = shortlist->next;
}
return longlist;
}
else
{
return NULL;
}
}
struct ListNode* getmeetnode(struct ListNode* head)
{
struct ListNode* fast, * slow;
fast = slow = head;
while (fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
if (fast == slow)
{
return fast;
}
}
return NULL;
}
struct ListNode* detectCycle(struct ListNode* head)
{
// 找到相遇点
struct ListNode* meetnode = getmeetnode(head);
if(meetnode == NULL)
{
return NULL;
}
// 断开为两个链表
struct ListNode* cur1, *cur2;
cur1 = meetnode->next;
meetnode->next=NULL;
cur2 = head;
// 找到两个链表的交点
struct ListNode* IntersectionNode = getIntersectionNode(cur1, cur2);
return IntersectionNode;
}