版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/HaloTrriger/article/details/80629617
链表带环是老生常谈的一个问题,链表带环衍生出了三个问题。
1. 判断链表是否带环
2. 计算环长
3. 求环的入口点
而这三个问题每个问题都建立在前一个问题的基础上才能解决。
一、判断链表是否带环
两个指针,一个fast,一个slow。从起点开始,fast一次走两步,slow一次走一步。如果它们能相遇,则链表一定带环,因为它们会在环内相遇。
二、计算环长
在上一题的基础,知道相遇点,从相遇点开始,再走一圈再回到这里的长度就是环长。
三、求环的入口点
第一种方法,知道相遇点和环长。fast从起点先走环长步,然后slow位于起点,此时它们同时一次走一步,当他们相遇时fast已经刚好走了一圈重新回到入口点,所以当他们相遇就是入口点。
代码如下:
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {}
};
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
if (pHead == NULL || pHead->next == NULL)
return NULL;
ListNode*fast = pHead;
ListNode*slow = pHead;
//找到快慢指针相遇点
while (fast&&fast->next)
{
fast = fast->next->next;
slow = slow->next;
if (fast == slow)
break;
}
//fast走环长
ListNode*tmp = fast;
fast = pHead;
while (tmp->next != slow)
{
tmp = tmp->next;
fast = fast->next;
}
//fast补上少走的一步
fast = fast->next;
//同时走
slow = pHead;
while (fast != slow)
{
fast = fast->next;
slow = slow->next;
}
return fast;
}
第二种方法,知道相遇点。fast从相遇点出发,slow从起点出发,一次走一步,再次相遇的点就是入口点。(为什么再次相遇的点是入口点,后面解释)
代码如下:
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {}
};
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
if (pHead == NULL || pHead->next == NULL)
return NULL;
ListNode*fast = pHead;
ListNode*slow = pHead;
//快慢指针同时走,找环内相遇点
while (fast&&fast->next)
{
fast = fast->next->next;
slow = slow->next;
if (fast == slow)//链表带环
{
slow = pHead;
break;
}
}
//两指针此时同时一次走一步,相遇点就是入口点
while (fast!=slow)
{
fast = fast->next;
slow = slow->next;
}
return fast;
}
这里解释:为什么再次相遇的点是入口点?
此处用图片直观解释
最后的最后,欢迎大家提问,有不懂的随时在线解答