-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path142. Linked List Cycle II (HashTable + Two Pointers) 20.3.27 Medium
More file actions
156 lines (126 loc) · 5.14 KB
/
142. Linked List Cycle II (HashTable + Two Pointers) 20.3.27 Medium
File metadata and controls
156 lines (126 loc) · 5.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
Given a linked list, return the node where the cycle begins. If there is no cycle, return null.
To represent a cycle in the given linked list, we use an integer pos which represents the position (0-indexed) in the linked list
where tail connects to. If pos is -1, then there is no cycle in the linked list.
Note: Do not modify the linked list.
Example 1:
Input: head = [3,2,0,-4], pos = 1
Output: tail connects to node index 1
Explanation: There is a cycle in the linked list, where tail connects to the second node.
Example 2:
Input: head = [1,2], pos = 0
Output: tail connects to node index 0
Explanation: There is a cycle in the linked list, where tail connects to the first node.
Example 3:
Input: head = [1], pos = -1
Output: no cycle
Explanation: There is no cycle in the linked list.
Follow up:
Can you solve it without using extra space?
Solution no.1: -------------------------------------------------- HashTable
------------------------------------------------ O(n) T, O(n) S
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def detectCycle(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if head is None: return None
HashTable = {}
while head.next:
if not head in HashTable:
HashTable[head] = 0
head = head.next
else:
return head # Only difference compared to 141. Linked List Cycle, here we need to return a node
# in 141. Linked List Cycle, we only need to return True or False
return None
Solution no.2: ----------------------------------- Two Pointers ---------------------------------- without extra space
------------------------------------------------ O(n) T, O(1) S
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def detectCycle(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
slow, fast = head, head
while fast and fast.next: # The first part checks if a cycle exists or not
slow = slow.next
fast = fast.next.next
if slow == fast:
break
else: # IMPORTANT !!!!!!!!!!!!!!!!!!! while...else...
# else is execuated when the while condition is not satisfied: i.e. fast == None => no cycle
return None
'''
The logic behind the 2nd part is like this:
Consider the following linked list, where E is the cylce entry and X, the crossing point of fast and slow.
H: distance from head to cycle entry E
D: distance from E to X
L: cycle length
_____
/ \
head_____H______E \
\ /
X_____/
If fast and slow both start at head, when fast catches slow, slow has traveled H+D+n1L and fast 2(H+D+n1L).
because slow = slow.next and fast = fast.next.next, and n1 is the number of cycle loop slow travels before meeting
Assume fast has traveled n2 loops in the cycle, we have:
2(H+D+n1L) = H + D + n2L --> H + D = (n2 - n1)L (there is no doubt fast travels more loop than slow, i.e. n2 > n1)
So, H = nL - D, where n == n2 - n1, it is a constant.
Thus if two pointers start from head and X, respectively, where they meet will be the cycle entry E
Why? let's consider when head travels H and reach E point, the slow travels nL - D from X point,
L - D is the distance counted from X to E and (n-1)L bring slow back to where it starts,
so, after traveling (n-1)L + L - D = nL -D, slow will also reach E point at that time,
i.e., the first time head and slow meet, the meeting point is the cycle entry E !
'''
while head != slow: # The second part determines the entry of the cycle if it exists
head = head.next
slow = slow.next
return head
Java Version:
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
if (head == null) {
return null;
}
ListNode fast = head, slow = head;
boolean flag = false;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
flag = true;
break;
}
}
if (! flag) {
return null;
}
while (head != slow) {
head = head.next;
slow = slow.next;
}
return head;
}
}