head, the head of a linked list, determine if the linked list has a cycle in it.
There is a cycle in a linked list if there is some node in the list that can be reached again by continuously following the
next pointer. Internally,
pos is used to denote the index of the node that tail's
next pointer is connected to. Note that
pos is not passed as a parameter.
true if there is a cycle in the linked list. Otherwise, return
Input: head = [3,2,0,-4], pos = 1
Explanation: There is a cycle in the linked list, where the tail connects to the 1st node (0-indexed).
Approach 1: Hash Table
To detect if a list is cyclic, we can check whether a node had been visited before. A natural way is to use a hash table.
We go through each node one by one and record each node’s reference (or memory address) in a hash table. If the current node is
null, we have reached the end of the list and it must not be cyclic. If current node’s reference is in the hash table, then return true.
Let n be the total number of nodes in the linked list.
- Time complexity : O(n). We visit each of the n elements in the list at most once. Adding a node to the hash table costs only O(1) time.
- Space complexity: O(n). The space depends on the number of elements added to the hash table, which contains at most n elements.
Approach 2: Floyd’s Cycle Finding Algorithm
Imagine two runners running on a track at different speed. What happens when the track is actually a circle?
The space complexity can be reduced to O(1)O(1) by considering two pointers at different speed — a slow pointer and a fast pointer. The slow pointer moves one step at a time while the fast pointer moves two steps at a time.
If there is no cycle in the list, the fast pointer will eventually reach the end and we can return false in this case.
Now consider a cyclic list and imagine the slow and fast pointers are two runners racing around a circle track. The fast runner will eventually meet the slow runner. Why? Consider this case (we name it case A) — The fast runner is just one step behind the slow runner. In the next iteration, they both increment one and two steps respectively and meet each other.
How about other cases? For example, we have not considered cases where the fast runner is two or three steps behind the slow runner yet. This is simple, because in the next or next’s next iteration, this case will be reduced to case A mentioned above.
- Time complexity : O(n). Let us denote n as the total number of nodes in the linked list. To analyze its time complexity, we consider the following two cases separately.
- Space complexity : O(1). We only use two nodes (slow and fast) so the space complexity is O(1).