环形链表 II

题目描述

给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

示例 1:

输入:head = [3,2,0,-4]
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。

思路

如上图,我们让两个指针同时指向首节点,然后移动指针,其中slow指针每次移动一步,fast每次移动两步。如果环存在,则两指针必然会在环上某处相遇。假设在图中c处。根据速度关系,fast指针的路程一定是slow指针的两倍,这里我设弧AB长为x,弧BC为y,弧CB为z,则有(x+y)*2=x+y+n*(y+z),其中n为fast指针在弧=环里走过的圈数,那么n>=1,两边同时消去一个(x+y),得x+y=n*(y+z),移项化简的x=(n-1)*(y+z)+z,注意到(n-1)*(y+z)其实是环长度的整数倍,所以很容易推出x=z。知道这个我们就可以让其中一个指针从A处出发,另外一指针依然在c处,然后同时移动,每次移动一步,那么最后就会在B处相遇了,也就得到我们的入环口处了。

解法

C++版本

Java版本

Python3版本

### 环形链表 II 的核心概念 环形链表 II 是一种经典的算法问题,主要涉及检测单向链表是否存在环以及找到环的入口节点。该问题的核心在于通过双指针技术(快慢指针)来解决复杂度较低的时间和空间需求。 #### 双指针法原理 在环形链表 II 中,可以利用两个指针——一个慢指针 `slow` 和一个快指针 `fast` 来遍历链表。具体来说,慢指针每次移动一步,而快指针每次移动两步。如果链表存在环,则这两个指针最终会在某个节点上相遇[^1]。 当发现两者相遇时,可以通过以下推导得出如何定位环的起始位置: 设: - 链表头结点到环起点的距离为 \(a\), - 环起点到首次相遇点的距离为 \(b\), - 环剩余部分长度为 \(c\), 则有如下关系成立: \[ \text{slow} \times (a+b) = \text{fast} \times (a+b+c) \] 由于 fast 移动速度是 slow 的两倍,因此可得方程: \[ 2(a + b) = a + n(b + c) + b \] 化简得到: \[ a = nc - nb = (n-1)(b+c)+c \] 这意味着从头节点出发的一个新指针与当前位于相遇点的指针同步前进,它们将在环的入口处再次重合[^4]。 #### C++ 实现代码示例 以下是基于上述理论的一种高效解决方案实现方式: ```cpp class Solution { public: ListNode *detectCycle(ListNode *head) { if (!head || !head->next) return nullptr; ListNode* slow = head; ListNode* fast = head; bool hasCycle = false; while(fast && fast->next){ slow = slow->next; // Move one step at a time. fast = fast->next->next; // Move two steps at a time. if(slow == fast){ // If they meet, there's a cycle. hasCycle = true; break; } } if(!hasCycle) return nullptr; // No cycle detected. slow = head; // Reset 'slow' to start from the beginning. while(slow != fast){ slow = slow->next; fast = fast->next; } return slow; // They will meet again at the entrance node. } }; ``` 此代码片段展示了如何使用双指针技巧有效地解决问题并返回环的第一个节点地址或者 NULL 表明无循环情况发生[^3]。 #### 时间与空间复杂度分析 时间复杂度方面,整个过程仅需一次完整的列表扫描即可完成操作,故总体时间为 O(n),其中 n 表示链表中的节点总数;至于额外使用的内存资源仅为常数级别变量存储,所以整体的空间消耗也是恒定不变即 O(1)[^2]。 ### 性能优化与其他方法探讨 除了采用双指针外还可以考虑其他策略比如哈希集合记录访问过的每一个节点直到重复为止从而判断是否有回路形成但是这种方法会增加更多的辅助储存单元使得实际运行效率降低并且违背了原题对于低开销的要求。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值