快慢指针和找环入口

用快慢指针的方式应该经过面试准备的人都知道了。

那么怎么找环的入口呢。

假设从链表开始的位置到环入口的距离为p,慢指针在环内走了的距离为c,假设慢指针一共走了n步,快指针一共做了2n步。

那么,有p+c=n

显然,从p+c这一点开始,慢指针再走n步,必然还会回到这个点。为啥?【因为经过了2n步,快指针到达了这一点,所以慢指针如果再走n步,也会到达这一点】

如果让快指针从链表头开始走n步,也会到达p+c这个位置,二者相遇的第一个地方,肯定是环入口。

看图

图里,AB=p,BD=c,由于慢指针走了n步,快指针走了2n步,所以慢指针再走n步还是到达D点。

【DB=c只是说,慢指针在环内走了c这么远,不一定是不到一圈,也可能慢指针在环内走了几圈之后才到达D点,此时我们假定BD长度是这路径的总长为c

所以,得到如下解决办法:

在快慢指针相遇之后,让快指针重新指向链表头,慢指针还在p+c位置,然后二者同时走p步,每次走一步。走完之后二者相遇的位置就是环入口了。

<think>好的,我现在需要详细理解C语言中使用快慢指针检测链表的原理。首先,我应该回忆一下链表的基本结构。链表由节点组成,每个节点包含数据指向下一个节点的指针的存在意味着某个节点的指针指向了链表中之前的某个节点,导致链表尾部形成循。 接下来,快慢指针方法的具体实现。根据用户提供的引用,比如引用[2]提到快指针每次比慢指针快一步,最终会相遇。这说明快慢指针的速度差是关键。通常,快指针每次移动两步,慢指针每次移动一步。为什么这样能检测呢? 假设链表有,当慢指针进入时,快指针已经在内。由于快指针每次比慢指针多走一步,两者之间的距离每次减少1,最终必然会相遇。这一点在引用[2]引用[4]中都有提到。比如引用[4]提到如果快指针每次走3步,速度差为2,可能导致无法相遇,这取决于的长度是否为速度差的因数。但常规情况下使用步长差1更稳妥。 再考虑数学证明。设外长度为L,长度为C。慢指针进入时,快指针的位置可能在内的某个点。假设相遇时慢指针走了t步,那么快指针走了2t步。快指针比慢指针多走n圈,即2t = t + nC,解得t = nC。这说明相遇时慢指针走了n圈的长度。此时,头指针相遇点指针同时移动,每次一步,最终会在起点相遇,如引用[1]所述。 需要注意特殊情况,比如链表为空或只有一个节点的情况,此时不会有。代码实现时需要处理这些边界条件。例如引用[3]中的代码可能涉及这些处理,但具体实现需要看完整代码。 总结下来,快慢指针检测的原理基于速度差相遇条件,数学上确保在有时必然相遇,无时快指针会先到达链表末尾。</think>### C语言中快慢指针检测链表的原理 #### 1. 基本思路 快慢指针法(Floyd判圈算法)通过两个指针以不同速度遍历链表。若链表存在,快指针最终会追上慢指针;若无,快指针会先到达链表尾部。核心步骤如下: - **慢指针(slow)**:每次移动1步 - **快指针(fast)**:每次移动2步 - **终止条件**:若两指针相遇,则存在;若快指针遇到`NULL`,则无[^2][^4]。 #### 2. 数学证明 假设链表外长度为$L$,长度为$C$,两指针相遇时: - 慢指针移动距离:$L + a$($a$为内移动距离) - 快指针移动距离:$L + a + nC$($n$为快指针内绕行的圈数) 由速度关系(快指针是慢指针的2倍)可得: $$2(L + a) = L + a + nC \implies L = nC - a$$ 此时,将**头指针**从链表起点出发,**相遇点指针**从相遇点出发,两者每次均移动1步。头指针移动$L$步后到达入口,而相遇点指针移动$L$步后相当于在内移动$nC - a + a = nC$,即回到入口。因此两者必然在入口相遇[^1][^4]。 #### 3. 代码实现示例 ```c #include <stdbool.h> struct ListNode { int val; struct ListNode *next; }; bool hasCycle(struct ListNode *head) { if (head == NULL || head->next == NULL) { return false; // 空链表或单节点无 } struct ListNode *slow = head; struct ListNode *fast = head->next; while (slow != fast) { if (fast == NULL || fast->next == NULL) { return false; // 快指针遇到尾部,无 } slow = slow->next; // 慢指针走1步 fast = fast->next->next; // 快指针走2步 } return true; // 相遇,存在 } ``` #### 4. 注意事项 - **步长选择**:快指针步长必须为2,若步长大于2(如3步),可能因长度与速度差不互质导致无法相遇[^4]。 - **边界条件**:需处理链表为空或单节点的情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值