Detect if a Linked List is Circular in DSA Go - Time & Space Complexity
We want to know how long it takes to check if a linked list loops back on itself.
How does the time needed grow as the list gets longer?
Analyze the time complexity of the following code snippet.
func isCircular(head *Node) bool {
if head == nil {
return false
}
slow, fast := head, head.next
for fast != nil && fast.next != nil {
if slow == fast {
return true
}
slow = slow.next
fast = fast.next.next
}
return false
}
This code checks if a linked list has a cycle by moving two pointers at different speeds.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The loop that moves slow and fast pointers through the list.
- How many times: At most, it runs until fast pointer reaches the end or slow meets fast.
As the list gets longer, the loop runs more times but never more than the number of nodes.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | Up to 10 steps |
| 100 | Up to 100 steps |
| 1000 | Up to 1000 steps |
Pattern observation: The number of steps grows roughly in a straight line with the list size.
Time Complexity: O(n)
This means the time to check grows directly with the number of nodes in the list.
[X] Wrong: "The loop runs forever if the list is circular, so it never finishes."
[OK] Correct: The fast and slow pointers will meet inside the loop, stopping the check early.
Understanding this helps you show how to detect cycles efficiently, a common real-world problem.
"What if we used only one pointer to check for a cycle? How would the time complexity change?"
Practice
Solution
Step 1: Understand linked list structure
A linked list is a chain of nodes where each node points to the next node.Step 2: Define circular linked list
If the last node points back to any previous node, it creates a loop, making the list circular.Final Answer:
The last node points back to one of the previous nodes, forming a loop -> Option AQuick Check:
Circular linked list means loop in nodes = D [OK]
- Thinking circular means sorted list
- Confusing empty list with circular
- Assuming single node list is always circular
Solution
Step 1: Understand Floyd's cycle detection
Use two pointers: slow moves one step, fast moves two steps. If they meet, list is circular.Step 2: Check code correctness
for slow != nil && fast != nil && fast.Next != nil { slow = slow.Next; fast = fast.Next.Next; if slow == fast { return true } } return false correctly moves slow by one and fast by two steps and checks for equality inside the loop.Final Answer:
for slow != nil && fast != nil && fast.Next != nil { slow = slow.Next; fast = fast.Next.Next; if slow == fast { return true } } return false -> Option CQuick Check:
Two pointers moving at different speeds detect loop = B [OK]
- Moving fast pointer only one step
- Not checking fast.Next for nil
- Checking slow == fast outside loop
type Node struct { Val int; Next *Node }
func isCircular(head *Node) bool {
slow, fast := head, head
for fast != nil && fast.Next != nil {
slow = slow.Next
fast = fast.Next.Next
if slow == fast {
return true
}
}
return false
}
// List: 1 -> 2 -> 3 -> 4 -> 2 (loop back to node with value 2)
node1 := &Node{1, nil}
node2 := &Node{2, nil}
node3 := &Node{3, nil}
node4 := &Node{4, nil}
node1.Next = node2
node2.Next = node3
node3.Next = node4
node4.Next = node2
fmt.Println(isCircular(node1))Solution
Step 1: Analyze linked list structure
The last node (node4) points back to node2, creating a loop.Step 2: Trace Floyd's cycle detection
Slow and fast pointers will eventually meet inside the loop, so function returns true.Final Answer:
true -> Option AQuick Check:
Loop exists, so output is true [OK]
- Assuming no loop returns true
- Confusing pointer equality with value equality
- Ignoring fast.Next nil check
func isCircular(head *Node) bool {
slow, fast := head, head
for fast != nil {
slow = slow.Next
fast = fast.Next.Next
if slow == fast {
return true
}
}
return false
}Solution
Step 1: Review loop condition
The loop only checks fast != nil, but fast.Next might be nil causing runtime error on fast.Next.Next.Step 2: Correct loop condition
Adding fast.Next != nil in the loop condition prevents nil pointer dereference when accessing fast.Next.Next.Final Answer:
The loop condition should check fast.Next != nil to avoid nil pointer dereference -> Option BQuick Check:
Check fast and fast.Next to avoid errors [OK]
- Not checking fast.Next leads to runtime panic
- Moving slow pointer two steps is incorrect
- Returning false inside loop prematurely
Solution
Step 1: Detect the loop using two pointers
Use Floyd's cycle detection to find if slow and fast pointers meet inside the loop.Step 2: Count loop length
Once pointers meet, keep one pointer fixed and move the other pointer forward until it meets the fixed pointer again, counting the steps taken.Final Answer:
After detecting the loop, keep one pointer fixed and move the other until they meet again, counting steps -> Option DQuick Check:
Loop length = steps between pointer meetings [OK]
- Counting nodes until nil in circular list causes infinite loop
- Using map wastes extra memory
- Returning total nodes ignores loop length
Ready to prove it?
Pass the test and this pattern moves unknown
