目录
题目要求
手搓一个简易带环链表
代码实现
题目要求
给定一个链表的头节点 head,返回链表开始入环的第一个节点,如果链表无环,则返回NULL
手搓一个简易带环链表
代码演示:
struct ListNode* n1 = (struct ListNode*)malloc(sizeof(struct ListNode));
assert(n1);
struct ListNode* n2 = (struct ListNode*)malloc(sizeof(struct ListNode));
assert(n2);
struct ListNode* n3 = (struct ListNode*)malloc(sizeof(struct ListNode));
assert(n3);
struct ListNode* n4 = (struct ListNode*)malloc(sizeof(struct ListNode));
assert(n4);
n1->val = 3;
n2->val = 2;
n3->val = 0;
n4->val = -4;
n1->next = n2;
n2->next = n3;
n3->next = n4;
n4->next = n2;
代码实现
代码演示:
struct ListNode* detectCycle(struct ListNode* head)
{
struct ListNode* slow = head;
struct ListNode* fast = head;
while (fast != NULL && fast->next != NULL)
{
slow = slow->next;
fast = fast->next->next;
// 求入口点
if (slow == fast)
{
struct ListNode* meet = slow;
while (meet != head)
{
meet = meet->next;
head = head->next;
}
return meet;
}
}
return NULL;
}
代码解析:
代码思路(前提:slow 一次走一步,fast 一次走两步):
假设从 头节点 到 环的入口节点 的距离为:L
从 环的入口节点 到 fast 和 slow 的相遇 距离为:X
环的长度为:C
那么 头节点 到 slow 的距离是:L + X
头节点到 fast 的距离是:L + n*C + X(n是slow进环前,fast在环内走的圈数)
且已知 fast 是 slow 的 2 倍,得出以下等式:
2*(L + X) = L + n*C + X
= L + X = n*C
= L = n*C - X
= L = (n-1)*C + C - X
且不论 (n-1)*C 是多少,都是 fast 在圈内走的整数圈,都会走到相遇节点,所以可以直接忽略 (n-1)*C 这个式子
所以原式等于 L = C - X ;L 就是 从头节点 到环的入口节点的距离,C - X 就是 fast 和 slow 的相遇节点到 入口节点的距离
那么一个指针从头节点开始走,一个指针从相遇节点开始走,这两个节点同时走,当他们的地址相等时,那么这个节点就是环的入口节点
代码逻辑:
套用上一章的代码:数据结构 ——— 单链表oj题:环形链表(判断链表是否带环)-CSDN博客
当代码走到 fast == slow 的时候,就说此链表是环状链表且相遇了,那么就一个指针从头节点开始走,一个指针从相遇节点开始走,走到两个节点的地址相等时,此节点就是环的入口节点
代码验证: