- 带环链表:尾节点的next指向链表中的任意点(甚至可能指向它自己)
思考
接下来有几个问题需要我们来思考一下:
Q1
slow一次走1步,fast一次走2步,他们一定会相遇吗?(slow在走满一圈之前)
假设链表带环,两个指针最后都会进入环,快指针先进环,慢指针后进环。如果是最差情况:两个指针之间的距离刚好就是环的长度,那么当慢指针刚进环时,就和快指针相遇了。若两者相距N,如图所示,此时,两个指针每移动一次,之间距离缩小一步,因为是整数,所以总会缩小到0。
所以它们一定会相遇!
Q2
slow一次走1步,fast一次走3步,他们一定会相遇吗?
- 设N是slow开始入环,fast的最初开始追击的距离,C是环的长度。
- 如果N是偶数第一轮就直接追上了。
- 如果N是奇数,C是奇数,C-1是偶数,第二轮也追上了。
- 如果N是奇数,C是偶数,C-1是奇数,永远追不上。
若第一轮没有追上,那么它们之间就差了-1,fast在前面,那么我们可以看C-1的奇偶,如果C-1是偶数,那么
而如果C-1是个奇数,那么
请独立思考
如果N是奇数,C是偶数,那么就追不上。这个条件是否成立?请证明!
其实这个条件是不存在的,不可能会出现这种情况!
经过分析我们可以知道,当N是奇数,C是偶数的时候,这个式子不成立,所以这种情况一定不存在!所以 slow一次走1步,fast一次走3步,他们一定会相遇!
Q3
slow一次走n步,fast一次走m步,他们一定会相遇吗?(m>n>1)
这个和Q2有相似之处。
- 如果 N%(m-n) == 0 第一圈就直接追上了。
- 如果 N%(m-n) == x 第一圈也追不上了。
- 如果 (C-x)%(m-n) == 0 第二圈就追上了。
- 如果 (C-x)%(m-n) != 0 永远追不上了。
Q4
请证明:
让一个指针slow从链表起始位置开始遍历链表,同时让一个指针fast从判环时相遇点的位置开始绕环运行,注意slow每次走1步,fast每次走1步,最终肯定会在入口点的位置相遇。
速度是二倍关系,那么相同时间里,fast的路程也是slow路程的2倍
得证。
同时这个思路也可以用在Q2的独立思考题里。
通过这个结论,我们就可以找到入口点了!!
例题
环形链表1
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true 。 否则,返回 false 。
输入:head = [3,2,0,-4], pos = 1 输出:true 解释:链表中有一个环,其尾部连接到第二个节点。
思路:快慢指针,即慢指针一次走一步,快指针一次走两步,两个指针从链表起始位置开始往后走,如果链表带环则一定会在环中相遇,否则快指针率先走到链表的末尾。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
bool hasCycle(struct ListNode *head)
{
struct ListNode *faster=head;
struct ListNode *slow=head;
//一起走faster走2步 slow走1步--保持相对速度
while(faster && slow && faster->next)
{
faster=faster->next->next;
slow=slow->next;
if(slow == faster)
{
return true;
}
}
return false;
}
环形链表2
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
输入:head = [3,2,0,-4], pos = 1 输出:返回索引为 1 的链表节点 解释:链表中有一个环,其尾部连接到第二个节点。
思路:用Q4的结论:
让一个指针slow从链表起始位置开始遍历链表,同时让一个指针fast从判环时相遇点的位置开始绕环运行,注意slow每次走1步,fast每次走1步,最终肯定会在入口点的位置相遇。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode *detectCycle(struct ListNode *head)
{
struct ListNode *slow=head;
struct ListNode *fast=head;
struct ListNode *meet=NULL;
while(fast && fast->next)
{
fast=fast->next->next;
slow=slow->next;
if(fast == slow)
{
slow=head;
while(fast != slow)
{
slow=slow->next;
fast=fast->next;
}
return fast;
}
}
return NULL;
}