前言
在解决问题之前,我们先来了解一下什么是环形链表,我们以leetcode上的一道题目来感受一下,
读者可以先尝试自己做一下或者直接看下面题目的图片。
题目链接:. - 力扣(LeetCode)
leetcode141.环形链表
从图片中我们可以很容易看出,环形链表就是链表中的某一个节点与链表的另外一个节点相连接,而形成的环状结构。那么我们怎么判断一个链表是否为环形链表呢?我们可以把环状结构看成一个圆,那么我们可以定义快慢指针,以指针是否会相遇为判断条件,如果相遇,那么它就是一个带环的链表,否则它就不带环。下面是代码实现。
bool hasCycle(struct ListNode *head) {
struct ListNode*slow=head;
struct ListNode*fast=head;
while(fast&&fast->next)
{
slow=slow->next;
fast=fast->next->next;
if(slow==fast){return true; }
}
return false;
}
循环的结束条件为快指针以及快指针的下一个节点是否为空,如果为空就证明链表不带环,否则快慢指针就一定会相遇。
那么fast一次走两步时一定会相遇,那么fast一次走三步,四步,五步呢,下面我以fast一次走三步为例来推断是否在所有情况下fast和slow一定会相遇。
当N和C都为偶数时,slow和fast一定可以相遇,也就可以证明slow和fast一定可以相遇。
leetcode142.环形链表II
题目链接:. - 力扣(LeetCode)
第一种思路:
这道题目依旧是使用了快慢指针法。先通过快慢指针找到相遇的节点,一边从相遇的节点开始走,一边从头节点开始走,当前者与后者相遇的时候,此时即为环形链表的头节点。
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode*slow=head;
struct ListNode*fast=head;
while(fast&&fast->next)
{
slow=slow->next;
fast=fast->next->next;
if(slow==fast)
{
struct ListNode*meet=slow;
while(head!=meet)
{
head=head->next;
meet=meet->next;
}
return meet;
}
}
return NULL;
}
第二种思路:
还是使用快慢指针,先是找到相遇点,将相遇点的next指针指向空,这样这道题就变成了找相交链表的相交点。
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB)
{
struct ListNode*curA=headA;
struct ListNode*curB=headB;
int lenA=0,lenB=0;
while(curA->next)
{
curA=curA->next;
lenA++;
}
while(curB->next)
{
curB=curB->next;
lenB++;
}
if(curA!=curB)
{
return NULL;
}
int len=abs(lenA-lenB);
struct ListNode*shortlist=headA;
struct ListNode*longlist=headB;
if(lenA>lenB)
{
shortlist=headB;
longlist=headA;
}
while(len--)
{
longlist=longlist->next;
}
while(longlist!=shortlist)
{
longlist=longlist->next;
shortlist=shortlist->next;
}
return longlist;
}
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode*slow=head;
struct ListNode*fast=head;
while(fast&&fast->next)
{
slow=slow->next;
fast=fast->next->next;
if(slow==fast)
{
struct ListNode*meet=slow;
struct ListNode*newhead=meet->next;
meet->next=NULL;
struct ListNode*a=getIntersectionNode(head,newhead);
return a;
}
}
return NULL;
}
我们来证明一下第一种方法
推出的表达式中c-N是环形链表的头节点和相遇点的距离,不管fast走多少圈,环形链表的头节点
与slow和fast的相遇点的距离都和链表与环形链表的头节点的距离相同。