[Leetcode力扣 142] Linked List Cycle II

it2025-04-11  17

一、题目描述

给一个链表,如果里面有环,输出环的起点,否则输出空指针

二、解法一:判断节点对应的指针是否出现过

这是最容易想到的解法,因为一个节点的地址可以唯一确定这个节点,只要沿着链表移动,看节点对应的地址是否出现过就行了,unordered_set比set查找快一点,所以可以用unordered_set。代码如下:

/** * 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) { unordered_set<ListNode*> mp; while(head) { if(mp.count(head) != 0) return head; mp.insert(head); head = head->next; } return nullptr; } };

三、解法二:快慢指针

解法一时间效率还可以,但是需要O(n)的空间,不符合题目要求,所以需要新的方法。

链表判环可以使用快慢指针的方法,慢指针每次走一步,快指针每次走两步,如果链表中有环,那么快慢指针一定会相遇。

但是快慢指针的相遇点可能是环的任意位置,而本题需要找到环的入口点,那么应该怎么办呢?

实际上这里有一个简单的数学关系,设head为头节点,entry为入口点,meet为相遇点,head到entry的距离是L1,entry到meet的距离为L2,meet再到entry的距离为L3,也就是说整个环的长度为L2+L3。那么对于快慢指针相遇的情况,慢指针走的距离为L1+L2,快指针走的距离为L1+L2+n(L3+L2),因为快慢指针能相遇的话,快指针一定比慢指针多走了n圈,而快指针走的总距离是慢指针的两倍,所以L1+L2=n(L3+L2),由此可以得到L1=(n-1)(L2+L3)+L3,即L1的长度为L3加上固定圈数的环的长度。所以如果快慢指针相遇以后,meet和head一起移动,他俩相遇的地方就是entry点。

想想这个道理:meet可能会在环里转很多圈,但不论转多少圈,都会回到它开始的位置,所以meet和head一起走,一定会在entry处相遇。

代码如下:

/** * 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) { if(!head) return nullptr; ListNode *slow = head, *fast = head, *entry = head; while(fast->next && fast->next->next) { slow = slow->next; fast = fast->next->next; if(slow == fast) { while(slow != entry) { slow = slow->next; entry = entry->next; } return entry; } } return nullptr; } };

 

最新回复(0)