题目链接
题目描述
给定一个链表,返回链表开始入环的第一个节点。 从链表的头节点开始沿着 next 指针进入环的第一个节点为环的入口节点。如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意,pos 仅仅是用于标识环的情况,并不会作为参数传递到函数中。
说明:不允许修改给定的链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。
提示:
链表中节点的数目范围在范围 [0, 104] 内
-105 <= Node.val <= 105
pos 的值为 -1 或者链表中的一个有效索引
解题思路
map法比较简单,但是会浪费空间
此处只需要记住map也可以存储出现过得节点就可以了
此处重点说一下双指针的解法
利用快慢指针,fast指针一次走两步,slow指针一次走一步
如果没有环的话,总会有一步fast==NULL或者fast->next==NULL,这时直接返回NULL即可
如果有环的话,slow和fast总会相遇,因为fast始终比slow快一步,类似于操场跑圈,如果一个人一直比你跑得快,你俩在操场上一直跑,总会有一个时间两个人会相遇
假设链表头部到环的入口的长度为a,环有b个节点
根据题目可知,fast走的步数为slow的两倍,有 fast=2*slow
又因为fast比slow走的快,两者同一个起点,fast要么比slow先进入环(a>0的时候),或者fast和slow同时进入环(a==0的时候),当两者再一次相遇后,说明fast最少套了slow一圈,所以假设fast套了slow n圈,那么有fast=n*b+slow
由两式子可以推导出slow=n*b,fast=2*n*b,说明当fast走了n个周长时,slow走了2n个周长
又有从链表的起点走k步能到环的起点,那么有k=a+nb,走a步说明第一次到入口节点,其后每加一次b,就说明就过一次入口节点(跑完一圈回到起点)
又因为slow=nb,所以只要在想办法让slow走a步就可以让slow到环的入口节点,可以让fast回到起点,然后让fast和slow以相同的速度同时走,当fast和slow再次相遇,说明fast走了a步到达了环的入口,slow也走了a步到达了环的入口,所以两者相等
题解
双指针
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* fast=head;
ListNode* slow=head;
while(fast&&fast->next&&fast!=slow){
fast=fast->next->next;
slow=slow->next;
}
if(fast==NULL&&fast->next==NULL) return NULL;
fast=head;
while(fast!=slow){
fast=fast->next;
slow=slow->next;
}
return fast;
}
};
map
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
map<ListNode*,int> ma;
while(head){
if(ma[head]!=0) return head;
ma[head]++;
head=head->next;
}
return NULL;
}
};