Linked List Cycle
You're given the head of a singly linked list. Return true if following next links from the head ever brings you back to a node you've already visited (the list has a cycle), and false if you eventually reach null. The examples write the list as its values plus pos, the index of the node the tail links back to; pos = -1 means the tail points to null. Your function receives only head, not pos. Can you use O(1) extra memory?
Examples
head = [3,2,0,-4], pos = 1 returns true
The tail, -4, links back to the node at index 1 (value 2). Walking from the head visits 3, 2, 0, -4, 2, 0, -4, and so on, never reaching null.
head = [1], pos = -1 returns false
The single node's next is null, so the walk ends after one node and nothing is visited twice.
Constraints
- 0 <= n <= 10^4
Hints
If two runners moved at different speeds around a track, what would tell you the track is a loop?
Use two pointers that traverse the list at different speeds.
Advance slow by one node and fast by two. If fast ever hits null, there is no cycle; if slow and fast meet at the same node, you have proved a cycle.
Drill This: Your Approach First
Approach
Floyd's tortoise and hare: move slow one node per step and fast two. Without a cycle, fast reaches null and you return false. With a cycle, both pointers end up circling it, and the gap between them shrinks by one node each step, so fast catches slow within one lap. Compare node identity, not values.
Time
O(n)
Space
O(1)
Pitfall
Solutions
public class Solution {
public boolean hasCycle(ListNode head) {
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) return true;
}
return false;
}
}class Solution:
def hasCycle(self, head) -> bool:
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow is fast:
return True
return False