Solution 1
对 0141. Linked List Cycle 的扩展,因此我们同样可以使用哈希表实现。
- 时间复杂度: O ( N ) O(N) O(N),其中 N N N为输入链表的长度,线性遍历一次
- 空间复杂度: O ( N ) O(N) O(N),其中 N N N为输入链表的长度,哈希表占用,每个节点一个空间
/**
* 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 == nullptr) {
return head;
}
unordered_set<ListNode*> checked;
while (head != nullptr) {
if (checked.find(head) != checked.end()) {
return head;
}
checked.insert(head);
head = head->next;
}
return nullptr;
}
};
Solution 2
同样使用快慢指针法,只是需要提前确认一个性质:两个指针分别一次走一步和两步,那么他们一定能在慢指针走第一周的情况下相遇。
记head到环起点的距离为a,二者从a开始到相遇位置距离为b,环的剩下部分为c,快指针已经在环上绕了n圈,那么有一个走过路程的关系
a + n ( b + c ) + b = 2 ( a + b ) a + n(b + c) + b = 2(a + b) a+n(b+c)+b=2(a+b)
简化后得到:
a = c + ( n − 1 ) ( b + c ) a = c + (n - 1) (b + c) a=c+(n−1)(b+c)
一开始我没看明白啥意思,后来反应过来了,右侧一项表示从现在相遇位置开始走这么多会回到环起点位置,这个距离正好等于head到环起点位置。
那么,额外增加的实现,就是在确认存在环之后,再用两个指针,一个从head出发,一个从相遇位置出发,每次均走一步,二者再次相遇位置一定是起点。
- 时间复杂度: O ( N ) O(N) O(N),其中 N N N为输入链表的长度,因为慢指针一定在一周内碰到快指针,因此其遍历时间复杂度为 O ( N ) O(N) O(N),对应地快指针的时间复杂度为 O ( 2 N ) = O ( N ) O(2N) = O(N) O(2N)=O(N),然后再照一次,同样不到一周的一次线性遍历,总复杂度 O ( N + N ) = O ( N ) O(N + N) = O(N) O(N+N)=O(N)
- 空间复杂度: O ( 1 ) O(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) {
if (head == nullptr || head->next == nullptr) {
return nullptr;
}
auto slow = head;
auto fast = head;
// 利用快慢指针是否相遇确定是否存在环
while (fast != nullptr && fast->next != nullptr) {
slow = slow->next;
fast = fast->next->next;
if (fast == slow) { break; }
}
if (fast == nullptr || fast->next == nullptr) {
return nullptr;
}
// 存在环,找到起点位置
fast = head;
while (slow != fast) {
// cout << fast-> val << " " << slow->val << endl;
slow = slow->next;
fast = fast->next;
}
return fast;
}
};
Solution 3
Solution 1的Python实现
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
if head is None:
return None
checked = set()
while head is not None:
if head in checked:
return head
checked.add(head)
head = head.next
return None
Solution 4
Solution 2的Python实现