Detect if a Linked List is Circular in DSA C++ - Time & Space Complexity
We want to know how long it takes to check if a linked list loops back on itself.
The question is: how does the time needed grow as the list gets longer?
Analyze the time complexity of the following code snippet.
bool isCircular(Node* head) {
if (!head) return false;
Node* slow = head;
Node* fast = head->next;
while (fast && fast->next) {
if (slow == fast) return true;
slow = slow->next;
fast = fast->next->next;
}
return false;
}
This code checks if a linked list has a loop by moving two pointers at different speeds.
- Primary operation: The while loop that moves two pointers through the list.
- How many times: At most, it runs once per node until pointers meet or list ends.
As the list grows, the number of steps grows roughly in a straight line with the number of nodes.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 steps |
| 100 | About 100 steps |
| 1000 | About 1000 steps |
Pattern observation: The steps increase directly with the list size, not faster or slower.
Time Complexity: O(n)
This means the time to detect a loop grows linearly with the number of nodes in the list.
[X] Wrong: "The fast pointer moves twice as fast, so the time is O(n/2), which is constant time."
[OK] Correct: Even though the fast pointer moves faster, the time still grows with list size. O(n/2) simplifies to O(n), so it is not constant time.
Understanding this helps you explain how to find loops efficiently, a common real-world problem in linked list questions.
"What if we used only one pointer moving one step at a time? 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 CQuick Check:
Circular linked list = last node points back [OK]
- Thinking circular means sorted list
- Confusing empty list with circular list
- Assuming single node list is always circular
Solution
Step 1: Understand slow and fast pointer method
Two pointers move at different speeds; if they meet, a loop exists.Step 2: Analyze code correctness
while(fast != nullptr && fast->next != nullptr) { slow = slow->next; fast = fast->next->next; if(slow == fast) return true; } return false; correctly moves slow by one and fast by two nodes, checking for equality inside the loop.Final Answer:
while(fast != nullptr && fast->next != nullptr) { slow = slow->next; fast = fast->next->next; if(slow == fast) return true; } return false; -> Option BQuick Check:
Slow-fast pointer meeting means circular [OK]
- Not checking fast and fast->next for nullptr
- Moving pointers at same speed
- Returning true without pointer meeting
struct Node {
int data;
Node* next;
};
Node* head = new Node{1, nullptr};
Node* second = new Node{2, nullptr};
Node* third = new Node{3, nullptr};
head->next = second;
second->next = third;
third->next = second; // creates a loop
bool isCircular(Node* head) {
Node* slow = head;
Node* fast = head;
while(fast != nullptr && fast->next != nullptr) {
slow = slow->next;
fast = fast->next->next;
if(slow == fast) return true;
}
return false;
}
std::cout << (isCircular(head) ? "Circular" : "Not Circular") << std::endl;Solution
Step 1: Analyze linked list structure
third->next points to second, creating a loop between second and third nodes.Step 2: Trace slow and fast pointers
Slow moves one step, fast moves two steps; they will meet inside the loop, returning true.Final Answer:
Circular -> Option AQuick Check:
Loop detected by slow-fast pointers = Circular [OK]
- Ignoring the loop created by third->next
- Assuming no loop means Not Circular
- Confusing pointer assignments
bool isCircular(Node* head) {
Node* slow = head;
Node* fast = head;
while(fast != nullptr) {
slow = slow->next;
fast = fast->next->next;
if(slow == fast) return true;
}
return false;
}Solution
Step 1: Check loop condition safety
fast->next->next is accessed, so fast->next must not be nullptr to avoid crash.Step 2: Correct loop condition
Change while(fast != nullptr) to while(fast != nullptr && fast->next != nullptr) to prevent null pointer dereference.Final Answer:
The loop condition should check fast->next != nullptr to avoid null pointer dereference -> Option AQuick Check:
Check fast and fast->next to avoid crash [OK]
- Not checking fast->next leads to runtime error
- Moving slow pointer incorrectly
- Returning false too early
Solution
Step 1: Detect loop using slow and fast pointers
Use two pointers moving at different speeds; if they meet, a loop exists.Step 2: Find the node before loop start and break the loop
Reset one pointer to head, move both one step until they meet; the node before meeting point is loop end. Set its next to nullptr.Final Answer:
Detect the loop using slow and fast pointers, then find the node before the loop start and set its next to nullptr -> Option DQuick Check:
Find loop start, break link to remove circular [OK]
- Deleting nodes unnecessarily
- Reversing list does not remove loop
- Setting head to nullptr loses entire list
Ready to prove it?
Pass the test and this pattern moves unknown
