Bird
Raised Fist0
DSA Goprogramming~15 mins

Detect if a Linked List is Circular in DSA Go - Deep Dive

Choose your learning style10 modes available
Overview - Detect if a Linked List is Circular
What is it?
A linked list is a chain of nodes where each node points to the next one. Sometimes, the last node points back to an earlier node, forming a loop or circle. Detecting if a linked list is circular means checking if such a loop exists. This helps avoid infinite loops when processing the list.
Why it matters
Without detecting circular linked lists, programs can get stuck forever following the loop, causing crashes or freezes. This problem appears in many real systems like network routing or memory management. Detecting loops ensures safe and correct handling of linked lists.
Where it fits
Before this, you should understand what a linked list is and how to traverse it. After this, you can learn how to remove loops or find the start of the loop. This topic fits in the study of linked list algorithms and cycle detection.
Mental Model
Core Idea
If you move through the list with two pointers at different speeds, they will meet if a loop exists.
Think of it like...
Imagine two runners on a circular track: one runs faster than the other. If the track is a loop, the faster runner will eventually catch up to the slower one.
Start -> Node1 -> Node2 -> Node3 -> Node4 -┐
                      ↑                      |
                      β””----------------------β”˜

Two pointers:
Slow pointer moves one step at a time.
Fast pointer moves two steps at a time.
If fast meets slow, list is circular.
Build-Up - 7 Steps
1
FoundationUnderstand Linked List Structure
πŸ€”
Concept: Learn what a linked list node is and how nodes connect.
A linked list node has two parts: data and a pointer to the next node. The list starts at a head node and ends when a node points to nil (no next node). Example in Go: ```go type Node struct { value int next *Node } head := &Node{value: 1} head.next = &Node{value: 2} head.next.next = &Node{value: 3} ``` This creates a simple chain: 1 -> 2 -> 3 -> nil.
Result
A chain of nodes connected by next pointers, ending with nil.
Understanding the basic linked list structure is essential before detecting loops, as loops break the normal end condition.
2
FoundationTraverse a Linked List Safely
πŸ€”
Concept: Learn how to move through a linked list node by node.
To visit each node, start at head and follow next pointers until nil: ```go current := head for current != nil { fmt.Println(current.value) current = current.next } ``` This prints all node values in order.
Result
Prints: 1 2 3
Traversal relies on reaching nil to stop; if the list loops, traversal never ends.
3
IntermediateRecognize Circular Linked List Problem
πŸ€”Before reading on: do you think a normal traversal loop will end if the list is circular? Commit to yes or no.
Concept: Understand why normal traversal fails on circular lists.
If the last node points back to an earlier node, the list has no nil end. Traversing will cycle forever: Example: Node3.next = Node1 Traversal: 1 -> 2 -> 3 -> 1 -> 2 -> 3 -> ... infinite loop.
Result
Traversal never ends, causing program to hang.
Knowing traversal fails on circular lists motivates the need for a detection method.
4
IntermediateUse Two Pointers to Detect Loop
πŸ€”Before reading on: do you think moving two pointers at different speeds can detect a loop? Commit to yes or no.
Concept: Introduce Floyd's Cycle Detection algorithm using slow and fast pointers.
Start two pointers at head: - slow moves one step at a time - fast moves two steps at a time If fast reaches nil, no loop. If fast meets slow, loop exists. Example code snippet: ```go slow, fast := head, head for fast != nil && fast.next != nil { slow = slow.next fast = fast.next.next if slow == fast { fmt.Println("Loop detected") break } } ```
Result
If loop exists, slow and fast pointers meet inside the loop.
Using two pointers at different speeds cleverly detects loops without extra memory.
5
IntermediateImplement Full Loop Detection Function
πŸ€”Before reading on: do you think the function should return true immediately when pointers meet? Commit to yes or no.
Concept: Write a complete Go function to detect circular linked list.
```go type Node struct { value 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 } // Example usage: // Create nodes n1 := &Node{value: 1} n2 := &Node{value: 2} n3 := &Node{value: 3} // Link nodes n1.next = n2 n2.next = n3 n3.next = n1 // creates loop fmt.Println(isCircular(n1)) // Output: true ```
Result
Function returns true if loop exists, false otherwise.
A clear, reusable function encapsulates the detection logic for practical use.
6
AdvancedFind Start Node of the Loop
πŸ€”Before reading on: do you think the meeting point of pointers is always the loop start? Commit to yes or no.
Concept: Extend detection to locate where the loop begins in the list.
After detecting loop (slow == fast), reset slow to head. Move slow and fast one step at a time. The node where they meet again is the loop start. ```go func findLoopStart(head *Node) *Node { slow, fast := head, head for fast != nil && fast.next != nil { slow = slow.next fast = fast.next.next if slow == fast { slow = head for slow != fast { slow = slow.next fast = fast.next } return slow } } return nil } ```
Result
Returns the node where the loop starts or nil if no loop.
Knowing the loop start helps fix or analyze circular lists in real applications.
7
ExpertUnderstand Time and Space Complexity
πŸ€”Before reading on: do you think this algorithm uses extra memory proportional to list size? Commit to yes or no.
Concept: Analyze efficiency of Floyd's algorithm in time and memory use.
Floyd's algorithm runs in O(n) time because each pointer moves through nodes at most a few times. It uses O(1) extra space since no additional data structures are needed. This is better than using a map or set to track visited nodes, which uses O(n) space. This efficiency makes it suitable for large or memory-limited systems.
Result
Fast detection with minimal memory use.
Understanding complexity guides choosing the best detection method for different scenarios.
Under the Hood
The algorithm uses two pointers moving at different speeds. If the list has a loop, the faster pointer will eventually catch up to the slower pointer inside the loop. This happens because the fast pointer laps the slow pointer like runners on a track. If no loop exists, the fast pointer reaches the end (nil) first.
Why designed this way?
This method was designed to detect loops without extra memory, unlike hash-based methods. It balances simplicity, speed, and memory efficiency. Alternatives like storing visited nodes require more space and are slower for large lists.
Head
 β”‚
 β–Ό
β”Œβ”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”
β”‚Node1β”‚ --> β”‚Node2β”‚ --> β”‚Node3β”‚ --> β”‚Node4β”‚
β””β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”˜
                                ↑       β”‚
                                β””-------β”˜

Slow pointer moves one step each loop.
Fast pointer moves two steps each loop.
They meet inside the loop if it exists.
Myth Busters - 3 Common Misconceptions
Quick: Does a linked list with no nil end always have a loop? Commit yes or no.
Common Belief:If a linked list does not end with nil, it must be circular.
Tap to reveal reality
Reality:A list might have a corrupted pointer or dangling reference without a proper loop. Not all non-nil ends form a valid loop.
Why it matters:Assuming any non-nil end is a loop can cause wrong conclusions and bugs in programs.
Quick: Can the slow and fast pointers meet outside the loop? Commit yes or no.
Common Belief:Slow and fast pointers can meet anywhere in the list, even if no loop exists.
Tap to reveal reality
Reality:They can only meet if a loop exists, because fast pointer moves faster and catches slow only in a cycle.
Why it matters:Misunderstanding this leads to false positives or incorrect loop detection.
Quick: Is the meeting point of slow and fast pointers always the loop start? Commit yes or no.
Common Belief:The node where slow and fast pointers meet is the start of the loop.
Tap to reveal reality
Reality:The meeting point is inside the loop but not necessarily the start. Additional steps are needed to find the loop start.
Why it matters:Confusing meeting point with loop start can cause errors when trying to remove or analyze the loop.
Expert Zone
1
The distance from head to loop start equals the distance from meeting point to loop start when moving pointers at same speed.
2
If the loop length is k, the fast pointer moves k steps more than slow pointer before meeting.
3
Floyd's algorithm can be adapted to detect cycles in other structures like graphs or sequences.
When NOT to use
Avoid Floyd's algorithm if you need to know all nodes in the loop or count loop length directly; use hash-based detection or specialized algorithms instead.
Production Patterns
Used in garbage collectors to detect cyclic references, network routing to detect loops, and debugging tools to find infinite loops in linked data.
Connections
Cycle Detection in Graphs
Builds-on the idea of detecting loops but in more complex structures with multiple paths.
Understanding linked list cycle detection helps grasp graph cycle detection algorithms like DFS with visited sets.
Racing Algorithms in Sports Timing
Shares the concept of two entities moving at different speeds to determine meeting points.
Knowing how runners lap each other on a track clarifies how pointers meet in cycle detection.
Memory Leak Detection
Uses similar cycle detection to find unreachable but still referenced objects in memory.
Detecting loops in linked structures is key to identifying memory leaks caused by cyclic references.
Common Pitfalls
#1Not checking if fast or fast.next is nil before moving pointers.
Wrong approach:for fast != nil { slow = slow.next fast = fast.next.next if slow == fast { return true } }
Correct approach:for fast != nil && fast.next != nil { slow = slow.next fast = fast.next.next if slow == fast { return true } }
Root cause:Missing fast.next check causes runtime error when fast.next is nil and fast.next.next is accessed.
#2Returning false immediately after first pointer move without full traversal.
Wrong approach:if head == nil { return false } slow, fast := head, head.next if slow == fast { return true } return false
Correct approach:slow, fast := head, head for fast != nil && fast.next != nil { slow = slow.next fast = fast.next.next if slow == fast { return true } } return false
Root cause:Checking pointers only once misses loops that appear later in the list.
Key Takeaways
A circular linked list has a loop where nodes connect back to earlier nodes, causing infinite traversal.
Floyd's Cycle Detection uses two pointers moving at different speeds to detect loops efficiently without extra memory.
Detecting loops prevents programs from hanging and helps maintain data integrity in linked structures.
Finding the loop start requires resetting one pointer and moving both at the same speed until they meet again.
Proper pointer checks prevent runtime errors and ensure reliable loop detection.

Practice

(1/5)
1. What does it mean if a linked list is circular?
easy
A. The last node points back to one of the previous nodes, forming a loop
B. The linked list has no nodes
C. The linked list nodes are sorted in ascending order
D. The linked list has only one node

Solution

  1. Step 1: Understand linked list structure

    A linked list is a chain of nodes where each node points to the next node.
  2. Step 2: Define circular linked list

    If the last node points back to any previous node, it creates a loop, making the list circular.
  3. Final Answer:

    The last node points back to one of the previous nodes, forming a loop -> Option A
  4. Quick Check:

    Circular linked list means loop in nodes = D [OK]
Hint: Circular means last node links back inside list [OK]
Common Mistakes:
  • Thinking circular means sorted list
  • Confusing empty list with circular
  • Assuming single node list is always circular
2. Which Go code snippet correctly checks if a linked list is circular using two pointers?
easy
A. for slow != nil && fast != nil { slow = slow.Next; fast = fast.Next; if slow == fast { return true } } return false
B. for slow != nil { slow = slow.Next; if slow == fast { return true } } return false
C. for slow != nil && fast != nil && fast.Next != nil { slow = slow.Next; fast = fast.Next.Next; if slow == fast { return true } } return false
D. for fast != nil && fast.Next != nil { fast = fast.Next.Next; if slow == fast { return true } } return false

Solution

  1. Step 1: Understand Floyd's cycle detection

    Use two pointers: slow moves one step, fast moves two steps. If they meet, list is circular.
  2. 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.
  3. 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 C
  4. Quick Check:

    Two pointers moving at different speeds detect loop = B [OK]
Hint: Fast pointer moves twice, slow moves once to detect loop [OK]
Common Mistakes:
  • Moving fast pointer only one step
  • Not checking fast.Next for nil
  • Checking slow == fast outside loop
3. What will be the output of this Go code snippet detecting circular linked list?
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))
medium
A. true
B. false
C. runtime error
D. infinite loop

Solution

  1. Step 1: Analyze linked list structure

    The last node (node4) points back to node2, creating a loop.
  2. Step 2: Trace Floyd's cycle detection

    Slow and fast pointers will eventually meet inside the loop, so function returns true.
  3. Final Answer:

    true -> Option A
  4. Quick Check:

    Loop exists, so output is true [OK]
Hint: Loop in list means function returns true [OK]
Common Mistakes:
  • Assuming no loop returns true
  • Confusing pointer equality with value equality
  • Ignoring fast.Next nil check
4. Find the bug in this Go code that tries to detect if a linked list is circular:
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
}
medium
A. The function should return false inside the loop when slow != fast
B. The loop condition should check fast.Next != nil to avoid nil pointer dereference
C. The slow pointer should move two steps instead of one
D. The fast pointer should start at head.Next instead of head

Solution

  1. Step 1: Review loop condition

    The loop only checks fast != nil, but fast.Next might be nil causing runtime error on fast.Next.Next.
  2. Step 2: Correct loop condition

    Adding fast.Next != nil in the loop condition prevents nil pointer dereference when accessing fast.Next.Next.
  3. Final Answer:

    The loop condition should check fast.Next != nil to avoid nil pointer dereference -> Option B
  4. Quick Check:

    Check fast and fast.Next to avoid errors [OK]
Hint: Always check fast.Next != nil before fast.Next.Next [OK]
Common Mistakes:
  • Not checking fast.Next leads to runtime panic
  • Moving slow pointer two steps is incorrect
  • Returning false inside loop prematurely
5. Given a linked list where the last node points back to the head node, how can you modify the detection function to also return the length of the loop?
hard
A. Return the total number of nodes in the list without checking for loops
B. Count nodes while traversing from head until reaching nil
C. Use a map to store visited nodes and count duplicates
D. After detecting the loop, keep one pointer fixed and move the other until they meet again, counting steps

Solution

  1. Step 1: Detect the loop using two pointers

    Use Floyd's cycle detection to find if slow and fast pointers meet inside the loop.
  2. 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.
  3. Final Answer:

    After detecting the loop, keep one pointer fixed and move the other until they meet again, counting steps -> Option D
  4. Quick Check:

    Loop length = steps between pointer meetings [OK]
Hint: Count steps between pointer meetings after loop detected [OK]
Common Mistakes:
  • Counting nodes until nil in circular list causes infinite loop
  • Using map wastes extra memory
  • Returning total nodes ignores loop length
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard