Bird
Raised Fist0
DSA Goprogramming

Detect if a Linked List is Circular in DSA Go

Choose your learning style10 modes available
Mental Model
A linked list is circular if you can keep following next pointers and eventually come back to the start node.
Analogy: Imagine walking around a circular track; if you keep walking forward, you will eventually return to where you started without stopping.
head -> 1 -> 2 -> 3 -> null
head -> 1 -> 2 -> 3 ->
           ↑       ↓
           ←-------
Dry Run Walkthrough
Input: list: 1 -> 2 -> 3 -> (3 points back to 1, making it circular)
Goal: Determine if the linked list loops back to an earlier node, making it circular
Step 1: Initialize two pointers: slow at head (1), fast at head (1)
head -> [slow->1] -> 2 -> 3 ->
head -> [fast->1] -> 2 -> 3 ->
Why: We start both pointers at the beginning to check for a cycle
Step 2: Move slow by one node to 2, fast by two nodes to 3
head -> 1 -> [slow->2] -> 3 ->
head -> 1 -> 2 -> [fast->3] ->
Why: Slow moves step by step, fast moves twice as fast to detect cycle quickly
Step 3: Move slow by one node to 3, fast by two nodes: from 3 back to 1 then to 2
head -> 1 -> 2 -> [slow->3] ->
head -> [fast->2] -> 3 -> 1 ->
Why: Fast pointer loops around due to cycle, slow moves forward
Step 4: Move slow by one node: from 3 back to 1, fast by two nodes: from 2 to 3 then 1
head -> [slow->1] -> 2 -> 3 ->
head -> 1 -> 2 -> [fast->1] ->
Why: Both pointers meet at node 1, confirming the cycle
Result:
head -> [slow->1] -> 2 -> 3 ->
head -> 1 -> 2 -> [fast->1] ->
Answer: The list is circular (cycle detected)
Annotated Code
DSA Go
package main

import "fmt"

type Node struct {
    val  int
    next *Node
}

func isCircular(head *Node) bool {
    if head == nil {
        return false
    }
    slow := head
    fast := head
    for fast != nil && fast.next != nil {
        slow = slow.next // move slow by one
        fast = fast.next.next // move fast by two
        if slow == fast {
            return true // cycle detected
        }
    }
    return false // no cycle
}

func main() {
    // Create nodes
    n1 := &Node{val: 1}
    n2 := &Node{val: 2}
    n3 := &Node{val: 3}

    // Link nodes
    n1.next = n2
    n2.next = n3
    n3.next = n1 // makes the list circular

    // Check if circular
    fmt.Println(isCircular(n1))
}
if head == nil { return false }
handle empty list edge case
slow := head fast := head
initialize two pointers at start
for fast != nil && fast.next != nil {
loop while fast pointer can move ahead
slow = slow.next // move slow by one
advance slow pointer by one node
fast = fast.next.next // move fast by two
advance fast pointer by two nodes
if slow == fast { return true }
if pointers meet, cycle exists
return false
no cycle found after traversal
OutputSuccess
true
Complexity Analysis
Time: O(n) because each node is visited at most twice by the two pointers
Space: O(1) because only two pointers are used regardless of list size
vs Alternative: Compared to using a hash set to store visited nodes (O(n) space), this uses constant space making it more efficient
Edge Cases
empty list (head is nil)
returns false immediately since no nodes exist
DSA Go
if head == nil { return false }
single node pointing to itself
detects cycle as slow and fast meet at the single node
DSA Go
if slow == fast { return true }
list with no cycle (last node points to nil)
returns false after fast pointer reaches end
DSA Go
for fast != nil && fast.next != nil
When to Use This Pattern
When you see a problem asking if a linked list loops back on itself, use the two-pointer (slow and fast) technique to detect cycles efficiently.
Common Mistakes
Mistake: Not checking if fast or fast.next is nil before moving fast pointer two steps
Fix: Add condition 'fast != nil && fast.next != nil' in the loop to avoid null pointer errors
Mistake: Moving slow and fast pointers incorrectly (e.g., both by one step)
Fix: Move slow by one step and fast by two steps to detect cycle properly
Summary
Detects if a linked list has a cycle by using two pointers moving at different speeds.
Use when you need to know if a linked list loops back to an earlier node.
If two pointers moving at different speeds meet, the list is circular.

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