Detect if a Linked List is Circular in DSA Javascript - 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.
function isCircular(head) {
let slow = head;
let fast = head;
while (fast !== null && fast.next !== null) {
slow = slow.next;
fast = fast.next.next;
if (slow === fast) {
return true;
}
}
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 while loop that moves slow and fast pointers through the list.
- How many times: At most, each pointer moves through the list nodes once until they meet or reach the end.
As the list grows, the number of steps increases 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 grow directly with the list size, not faster or slower.
Time Complexity: O(n)
This means the time to check grows in a straight line with the number of nodes in the list.
[X] Wrong: "The fast pointer moves twice as fast, so the time is half, or O(n/2)."
[OK] Correct: We ignore constants in Big-O, so O(n/2) is still O(n). The time still grows linearly with n.
Understanding this helps you explain how to detect loops efficiently, a common linked list question.
"What if we used only one pointer and checked visited nodes with extra memory? 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 DQuick 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 Floyd's cycle detection
Use two pointers: slow moves one step, fast moves two steps. If they meet, list is circular.Step 2: Eliminate wrong options
Checking head null only doesn't detect loops. Counting nodes or sorting is unrelated.Final Answer:
Use two pointers moving at different speeds and check if they meet -> Option BQuick Check:
Two-pointer cycle detection = correct method [OK]
- Only checking if head is null
- Trying to sort linked list to detect cycle
- Counting nodes without loop detection
class Node {
constructor(value) {
this.value = value;
this.next = null;
}
}
const head = new Node(1);
const second = new Node(2);
const third = new Node(3);
head.next = second;
second.next = third;
third.next = second; // creates a loop
function isCircular(head) {
let slow = head;
let fast = head;
while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
if (slow === fast) return true;
}
return false;
}
console.log(isCircular(head));Solution
Step 1: Analyze linked list structure
Nodes 1 -> 2 -> 3, and third node points back to second, creating a loop.Step 2: Trace two-pointer loop detection
Slow and fast pointers will eventually meet inside the loop, so function returns true.Final Answer:
true -> Option CQuick Check:
Loop detected = true [OK]
- Assuming no loop because list looks linear
- Confusing pointer equality check
- Expecting false without tracing pointers
function isCircular(head) {
let slow = head;
let fast = head;
while (fast.next && fast.next.next) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) return true;
}
return false;
}Solution
Step 1: Check while loop condition safety
fast.next.next is accessed without confirming fast is not null, can cause error if fast is null.Step 2: Correct condition to avoid runtime error
Condition should be while (fast && fast.next) to safely access fast.next.next.Final Answer:
The while condition should check if fast and fast.next exist -> Option AQuick Check:
Check fast and fast.next before accessing next nodes [OK]
- Not checking if fast is null before accessing fast.next.next
- Using == instead of === (not critical here)
- Moving slow pointer two steps incorrectly
function detectLoopStart(head) {
let slow = head;
let fast = head;
while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
if (slow === fast) {
// Loop detected
slow = head;
while (slow !== fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
}
return null;
}Solution
Step 1: Detect loop using two pointers
Slow and fast pointers meet inside the loop confirming a cycle.Step 2: Find loop start node
Reset slow to head, move slow and fast one step at a time until they meet again; this node is loop start.Final Answer:
The function returns the node where the loop starts by resetting slow to head and moving both pointers one step -> Option AQuick Check:
Reset slow and move both pointers to find loop start [OK]
- Returning true instead of loop start node
- Moving fast pointer incorrectly after detection
- Assuming slow and fast never meet
Ready to prove it?
Pass the test and this pattern moves unknown
