题目链接 142. 环形链表 II
本题的解法主要是两种,都是在141题判断是否有环的基础上进行的
方法1:hash法
- 遍历链表,所有节点都放在hash中
- 如果一个节点已经在hash中存在,说明该节点就是环的连接点
本方法时间复杂度为O(n),因为用到一个hash结构,所以空间复杂度为O(n),
方法2:双指针法(快慢指针法)
在141中已经知道快慢指针会在环中相遇,入下图:
在环上相遇后,记录第一次相遇点为Pos,连接点为Join,假设头结点到连接点的长度为LenA,连接点到第一次相遇点的长度为x,环长为R。
- 第一次相遇时,slow走的长度 S = LenA + x;
- 第一次相遇时,fast走的长度 2S = LenA + n*R + x;
- 所以可以知道,LenA + x = nR; LenA = nR -x;
对于 LenA = nR -x 这个公式,可以得到 第一次碰撞点Pos到连接点Join的距离=头指针到连接点Join的距离,因此,分别从第一次碰撞点Pos、头指针head开始走,相遇的那个点就是连接点。* (指针a走了LenA的距离,此时指针b走了nR -x的距离,nR 表示在换上走了n圈,位置还是在Pos,但是-x表示要从Pos位置后退x个位置,刚好到达Join这个连接点)
代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode *detectCycle(struct ListNode *head) {
if (!head || !head->next) {
return NULL;
}
//这里要注意,初始化时,慢指针指向头指针的下一个节点,快指针指向头指针后两个节点的位置
//如果慢指针初始为head,快指针初始为head->next,虽然能找到一个碰撞点,但是后面找环入口节点的时候就会有问题,无法遇到,进入死循环
struct ListNode *slow = head->next, *fast = head->next->next;
while (slow != fast) {
if (!fast || !fast->next) {
return NULL;
}
slow = slow->next;
fast = fast->next->next;
}
slow = head;
int pos = 0;
while (slow != fast) {
pos++;
slow = slow->next;
fast = fast->next;
}
return fast;
}
原文地址:https://www.cnblogs.com/xiaoshuai666/p/11391915.html
时间: 2024-11-09 03:04:14