题目描述
给定一个链表的头节点 head
,返回链表开始入环的第一个节点。 如果链表无环,则返回 null
。
如果链表中有某个节点,可以通过连续跟踪 next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 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
或者链表中的一个有效索引
**进阶:**你是否可以使用 O(1)
空间解决此题?
解答
/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {
public:ListNode *detectCycle(ListNode *head) {// 双指针法// 快慢指针分别为 fast 和slow,fast每次走两步,slow每次走一步// 快指针走的路程为f,慢指针走的路程为s// 环上节点数为b// 相遇必然是在环内,相遇时,f = 2s, f = s + nb, n为套的圈数// 故可得第一次相遇时 s = nb, 此时让快指针回到链表起点与慢指针同速度走// 若环之前长度为a,则 a + nb必然时在环的入口(所以必然快慢指针会在环口相遇)ListNode *fast = head, *slow = head;while(true){if(fast == nullptr || fast->next == nullptr){return nullptr;}fast = fast->next->next;slow = slow->next;// 第一次相遇在环内if(slow == fast) break;}// 快指针会头节点和慢指针同速度走fast = head;while(fast != slow){slow = slow->next;fast = fast->next;}return fast;}// 集合法(哈希表法)ListNode *detectCycle1(ListNode *head) {unordered_set<ListNode *> s;// 指针没到尾节点 且 当前节点没重复出现while(head && s.find(head) == s.end()){s.insert(head);head = head->next;}if(head){return head;}return NULL;}
};