Bird
Raised Fist0
Interview Prepoop-design-patternsmediumAmazonGoogleMicrosoftFlipkartSwiggyRazorpayPhonePeCRED

Singleton Pattern - Thread Safety, Double-Checked Locking & Lazy Init

Choose your preparation mode3 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
🎯
Singleton Pattern - Thread Safety, Double-Checked Locking & Lazy Init
mediumOOPAmazonGoogleMicrosoft

Imagine a logging system where multiple parts of an application need to write logs, but all must use the same logger instance to avoid conflicts and ensure consistency.

💡 The Singleton pattern ensures only one instance of a class exists and provides a global access point. Beginners often struggle with thread safety and lazy initialization, which are crucial for real-world applications where multiple threads may try to create instances simultaneously.
📋
Problem Statement

Design and implement the Singleton pattern ensuring thread safety and lazy initialization. Your implementation should prevent multiple instances from being created in a multithreaded environment, optimize performance by minimizing synchronization overhead, and optionally use language-specific features like enums for simplicity and safety.

The singleton instance must be lazily initialized (created only when first requested).The implementation must be thread-safe to prevent multiple instances in concurrent scenarios.Avoid unnecessary synchronization after the instance is initialized.Use language idioms where applicable (e.g., enum in Java).
💡
Example
Input"Multiple threads call getInstance() concurrently"
OutputAll threads receive the same singleton instance

Despite concurrent calls, only one instance is created and shared.

  • Multiple threads call getInstance() simultaneously → only one instance created
  • No calls to getInstance() → instance is never created (lazy initialization)
  • Repeated calls to getInstance() after initialization → no synchronization overhead
  • Singleton class is subclassed or cloned → should prevent multiple instances
⚠️
Common Mistakes
Not making constructor private

Multiple instances can be created externally, breaking singleton

Declare constructor as private or protected

Omitting synchronization in lazy initialization

Multiple threads may create multiple instances concurrently

Add synchronization or use thread-safe constructs

Synchronizing entire getInstance() method unnecessarily

Performance degrades due to locking on every call

Use double-checked locking to minimize synchronization

Not using volatile keyword with double-checked locking in Java

Instruction reordering can cause partially constructed instance to be visible

Declare instance as volatile

Allowing cloning or serialization to create new instances

Singleton property is violated by multiple instances

Override clone() and readResolve() methods to prevent this

🧠
Basic Singleton with Eager Initialization
💡 This approach introduces the Singleton concept simply by creating the instance at class load time. It is easy to understand but lacks lazy initialization and may waste resources if the instance is never used.

Intuition

Create the singleton instance when the class is loaded, so it is always available and thread-safe by default due to class loading guarantees.

Algorithm

  1. Declare a private static final instance of the class.
  2. Make the constructor private to prevent external instantiation.
  3. Provide a public static method to return the instance.
  4. Return the pre-created instance directly.
💡 The main challenge is understanding why the instance is created upfront and how private constructors enforce single instantiation.
</>
Code
class Singleton:
    _instance = object()  # Eagerly created dummy instance

    def __new__(cls):
        # Always return the same instance
        return cls._instance

# Driver code to test
if __name__ == '__main__':
    s1 = Singleton()
    s2 = Singleton()
    print(s1 is s2)  # True
Line Notes
class Singleton:Defines the Singleton class to encapsulate the pattern
_instance = object() # Eagerly created dummy instanceEagerly creates a single instance at class load time
def __new__(cls):Overrides __new__ to control instance creation
return cls._instanceAlways returns the same pre-created instance
public class Singleton {
    private static final Singleton instance = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return instance;
    }

    public static void main(String[] args) {
        Singleton s1 = Singleton.getInstance();
        Singleton s2 = Singleton.getInstance();
        System.out.println(s1 == s2); // true
    }
}
Line Notes
private static final Singleton instance = new Singleton();Eagerly creates the singleton instance at class load time
private Singleton() {}Prevents external instantiation
public static Singleton getInstance() {Provides global access to the instance
return instance;Returns the pre-created singleton instance
#include <iostream>

class Singleton {
private:
    static Singleton* instance;
    Singleton() {}
public:
    static Singleton* getInstance() {
        // Directly return the eagerly initialized instance
        return instance;
    }
};

// Eager initialization
Singleton* Singleton::instance = new Singleton();

int main() {
    Singleton* s1 = Singleton::getInstance();
    Singleton* s2 = Singleton::getInstance();
    std::cout << (s1 == s2) << std::endl; // 1 (true)
    return 0;
}
Line Notes
static Singleton* instance;Declares static pointer to hold singleton instance
Singleton() {}Private constructor to prevent external instantiation
static Singleton* getInstance() {Returns the singleton instance without checks
Singleton* Singleton::instance = new Singleton();Eagerly initializes the singleton instance
class Singleton {
  constructor() {
    if (Singleton.instance) {
      return Singleton.instance;
    }
    Singleton.instance = this;
  }
}

// Test
const s1 = new Singleton();
const s2 = new Singleton();
console.log(s1 === s2); // true
Line Notes
constructor() {Controls instance creation in JavaScript
if (Singleton.instance) {Returns existing instance if already created
Singleton.instance = this;Assigns the first created instance
console.log(s1 === s2);Confirms both variables point to the same instance
Complexity
TimeO(1)
SpaceO(1)

Instance is created once at class load, so getInstance() is constant time and space.

💡 For any number of calls, the instance is reused, so performance is optimal but initialization is not lazy.
Interview Verdict: Accepted

This approach is thread-safe due to class loading guarantees but wastes resources if the instance is never used.

🧠
Lazy Initialization with Synchronized Method
💡 This approach delays instance creation until first use and ensures thread safety by synchronizing the entire method, but synchronization overhead affects performance.

Intuition

Create the instance only when needed and synchronize the method to prevent multiple threads from creating multiple instances.

Algorithm

  1. Declare a private static instance initialized to null.
  2. Make the constructor private.
  3. Provide a public static synchronized method to check and create the instance if null.
  4. Return the singleton instance.
💡 The key difficulty is understanding how synchronization prevents race conditions but can slow down access after initialization.
</>
Code
import threading

class Singleton:
    _instance = None
    _lock = threading.Lock()

    def __new__(cls):
        with cls._lock:
            if cls._instance is None:
                cls._instance = super(Singleton, cls).__new__(cls)
        return cls._instance

# Driver code
if __name__ == '__main__':
    s1 = Singleton()
    s2 = Singleton()
    print(s1 is s2)  # True
Line Notes
import threadingImports threading module to use locks for synchronization
_lock = threading.Lock()Creates a lock to synchronize instance creation
with cls._lock:Ensures only one thread can execute instance creation at a time
if cls._instance is None:Checks if instance needs to be created
public class Singleton {
    private static Singleton instance;

    private Singleton() {}

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }

    public static void main(String[] args) {
        Singleton s1 = Singleton.getInstance();
        Singleton s2 = Singleton.getInstance();
        System.out.println(s1 == s2); // true
    }
}
Line Notes
private static Singleton instance;Declares instance without initialization for lazy loading
public static synchronized Singleton getInstance() {Synchronizes entire method to ensure thread safety
if (instance == null) {Creates instance only if it does not exist
return instance;Returns the singleton instance
#include <iostream>
#include <mutex>

class Singleton {
private:
    static Singleton* instance;
    static std::mutex mtx;
    Singleton() {}
public:
    static Singleton* getInstance() {
        std::lock_guard<std::mutex> lock(mtx);
        if (instance == nullptr) {
            instance = new Singleton();
        }
        return instance;
    }
};

Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;

int main() {
    Singleton* s1 = Singleton::getInstance();
    Singleton* s2 = Singleton::getInstance();
    std::cout << (s1 == s2) << std::endl; // 1 (true)
    return 0;
}
Line Notes
#include <mutex>Includes mutex for thread synchronization
static std::mutex mtx;Defines mutex to protect instance creation
std::lock_guard<std::mutex> lock(mtx);Locks mutex for the scope to ensure thread safety
if (instance == nullptr) {Checks if instance needs to be created
class Singleton {
  constructor() {
    if (Singleton.instance) {
      return Singleton.instance;
    }
    Singleton.instance = this;
  }

  static getInstance() {
    if (!Singleton.instance) {
      Singleton.instance = new Singleton();
    }
    return Singleton.instance;
  }
}

// Test
const s1 = Singleton.getInstance();
const s2 = Singleton.getInstance();
console.log(s1 === s2); // true
Line Notes
static getInstance() {Provides a static method to get the singleton instance
if (!Singleton.instance) {Checks if instance exists before creating
Singleton.instance = new Singleton();Creates the instance lazily
return Singleton.instance;Returns the singleton instance
Complexity
TimeO(1) per call, but synchronized
SpaceO(1)

Synchronization adds overhead on every call, even after initialization.

💡 For many calls, synchronization can slow down performance despite correctness.
Interview Verdict: Accepted but suboptimal

Thread safety is guaranteed but synchronization on every call is inefficient.

🧠
Double-Checked Locking with Volatile (Optimized Lazy Initialization)
💡 This approach minimizes synchronization overhead by locking only during the first instance creation, using double-checked locking and volatile keyword to ensure visibility and ordering.

Intuition

Check if instance exists without locking first; if null, synchronize and check again before creating. This avoids locking after initialization.

Algorithm

  1. Declare a private static volatile instance initialized to null.
  2. Make the constructor private.
  3. In getInstance(), first check if instance is null without locking.
  4. If null, synchronize and check again before creating the instance.
  5. Return the singleton instance.
💡 Understanding volatile and why double-checking is necessary to avoid race conditions is the main challenge.
</>
Code
import threading

class Singleton:
    _instance = None
    _lock = threading.Lock()

    @classmethod
    def getInstance(cls):
        if cls._instance is None:
            with cls._lock:
                if cls._instance is None:
                    cls._instance = cls()
        return cls._instance

    def __init__(self):
        pass

# Driver code
if __name__ == '__main__':
    s1 = Singleton.getInstance()
    s2 = Singleton.getInstance()
    print(s1 is s2)  # True
Line Notes
import threadingImports threading module to use locks for synchronization
class Singleton:Defines the Singleton class
_instance = NoneHolds the singleton instance, initially None
_lock = threading.Lock()Lock to synchronize instance creation
@classmethodDefines getInstance as a class method
def getInstance(cls):Provides global access to the singleton instance
if cls._instance is None:Double-check inside lock to prevent race condition
with cls._lock:Lock only if instance might need creation
cls._instance = cls()Create the singleton instance safely
return cls._instanceReturn the singleton instance
def __init__(self):Constructor (can be used for initialization)
public class Singleton {
    private static volatile Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }

    public static void main(String[] args) {
        Singleton s1 = Singleton.getInstance();
        Singleton s2 = Singleton.getInstance();
        System.out.println(s1 == s2); // true
    }
}
Line Notes
private static volatile Singleton instance;Volatile ensures visibility and ordering of writes
private Singleton() {}Prevents external instantiation
public static Singleton getInstance() {Provides global access to the singleton instance
if (instance == null) {Double-check inside synchronized block to avoid race
synchronized (Singleton.class) {Lock only when instance might be created
instance = new Singleton();Create the singleton instance safely
return instance;Return the singleton instance
#include <iostream>
#include <mutex>

class Singleton {
private:
    static Singleton* instance;
    static std::mutex mtx;
    Singleton() {}
public:
    static Singleton* getInstance() {
        if (instance == nullptr) {
            std::lock_guard<std::mutex> lock(mtx);
            if (instance == nullptr) {
                instance = new Singleton();
            }
        }
        return instance;
    }
};

Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;

int main() {
    Singleton* s1 = Singleton::getInstance();
    Singleton* s2 = Singleton::getInstance();
    std::cout << (s1 == s2) << std::endl; // 1 (true)
    return 0;
}
Line Notes
if (instance == nullptr) {Double-check inside lock to prevent race
std::lock_guard<std::mutex> lock(mtx);Lock only if instance might be created
instance = new Singleton();Create the singleton instance safely
return instance;Return the singleton instance
class Singleton {
  constructor() {
    if (Singleton.instance) {
      return Singleton.instance;
    }
    Singleton.instance = this;
  }

  static getInstance() {
    if (!Singleton.instance) {
      Singleton.instance = new Singleton();
    }
    return Singleton.instance;
  }
}

// Test
const s1 = Singleton.getInstance();
const s2 = Singleton.getInstance();
console.log(s1 === s2); // true
Line Notes
class Singleton {Defines the Singleton class
constructor() {Controls instance creation in JavaScript
if (Singleton.instance) {Returns existing instance if already created
Singleton.instance = this;Assigns the first created instance
static getInstance() {Static method to access singleton instance
if (!Singleton.instance) {Check if instance exists before creating
Singleton.instance = new Singleton();Create instance lazily
return Singleton.instance;Return the singleton instance
Complexity
TimeO(1) amortized
SpaceO(1)

Synchronization occurs only once during initialization, subsequent calls are fast.

💡 This approach balances thread safety and performance for real-world use.
Interview Verdict: Accepted and recommended

This is the preferred pattern for thread-safe lazy initialization in many languages.

🧠
Enum Singleton (Java Specific, Thread-Safe & Simple)
💡 Using enum to implement Singleton in Java is the simplest and safest way to guarantee thread safety and prevent multiple instantiations, including against serialization and reflection.

Intuition

Enums in Java are inherently single-instance per enum constant and provide implicit thread safety and serialization guarantees.

Algorithm

  1. Define an enum with a single element representing the singleton instance.
  2. Add any methods or fields needed inside the enum.
  3. Access the singleton instance via the enum constant.
  4. Rely on JVM guarantees for thread safety and serialization.
💡 Understanding that enum constants are instantiated once by JVM is key to this approach.
</>
Code
# Enum singleton is Java-specific; Python alternative is module-level singleton
class Singleton:
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

if __name__ == '__main__':
    s1 = Singleton()
    s2 = Singleton()
    print(s1 is s2)  # True
Line Notes
class Singleton:Defines singleton class as Python alternative to enum singleton
_instance = NoneHolds the singleton instance, initially None
def __new__(cls):Overrides __new__ to control instance creation
if cls._instance is None:Lazy initialization without thread safety
cls._instance = super().__new__(cls)Creates the instance once
return cls._instanceReturns the singleton instance
print(s1 is s2)Verifies singleton property
public enum Singleton {
    INSTANCE;

    public void someMethod() {
        System.out.println("Singleton using enum");
    }

    public static void main(String[] args) {
        Singleton s1 = Singleton.INSTANCE;
        Singleton s2 = Singleton.INSTANCE;
        System.out.println(s1 == s2); // true
        s1.someMethod();
    }
}
Line Notes
public enum Singleton {Defines enum singleton with one instance
INSTANCE;Singleton instance guaranteed by JVM
public void someMethod() {Example method inside singleton
Singleton s1 = Singleton.INSTANCE;Access singleton instance
// Enum singleton is not idiomatic in C++, use Meyers' singleton instead
#include <iostream>

class Singleton {
public:
    static Singleton& getInstance() {
        static Singleton instance; // Thread-safe lazy initialization
        return instance;
    }
    void someMethod() {
        std::cout << "Singleton using static local variable" << std::endl;
    }
private:
    Singleton() {}
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
};

int main() {
    Singleton& s1 = Singleton::getInstance();
    Singleton& s2 = Singleton::getInstance();
    std::cout << std::boolalpha << (&s1 == &s2) << std::endl; // true
    s1.someMethod();
    return 0;
}
Line Notes
static Singleton instance;Static local variable ensures thread-safe lazy initialization
Singleton(const Singleton&) = delete;Prevents copying
Singleton& operator=(const Singleton&) = delete;Prevents assignment
return instance;Returns the singleton instance
// JavaScript does not have enums like Java; use module pattern
const Singleton = (function() {
  let instance;

  function createInstance() {
    return { someMethod: () => console.log('Singleton instance') };
  }

  return {
    getInstance: function() {
      if (!instance) {
        instance = createInstance();
      }
      return instance;
    }
  };
})();

// Test
const s1 = Singleton.getInstance();
const s2 = Singleton.getInstance();
console.log(s1 === s2); // true
s1.someMethod();
Line Notes
let instance;Holds the singleton instance privately
function createInstance() {Creates the singleton object
if (!instance) {Lazy initialization on first call
return instance;Returns the singleton instance
Complexity
TimeO(1)
SpaceO(1)

Instance is created once by JVM or static initialization, with no synchronization overhead.

💡 This approach is the simplest and safest in Java, but language-specific.
Interview Verdict: Accepted and recommended for Java

Enum singleton is the best practice in Java for thread safety and simplicity.

📊
All Approaches - One-Glance Tradeoffs
💡 Double-checked locking is the best balance of thread safety and performance in most interviews; enum singleton is preferred in Java.
ApproachTimeSpaceStack RiskReconstructUse In Interview
1. Basic Eager InitializationO(1)O(1)NoNoExplain concept; not suitable if lazy init required
2. Lazy Initialization with Synchronized MethodO(1) but synchronized every callO(1)NoNoShow thread safety but mention performance drawback
3. Double-Checked Locking with VolatileO(1) amortized, minimal lockingO(1)NoNoPreferred approach for thread-safe lazy initialization
4. Enum Singleton (Java only)O(1)O(1)NoNoBest practice in Java; mention if language allows
💼
Interview Strategy
💡 Use this guide to understand the Singleton pattern from basic to advanced implementations, focusing on thread safety and lazy initialization, which are common interview topics.

How to Present

Step 1: Clarify the requirements - thread safety, lazy initialization, language constraints.Step 2: Present the basic eager initialization singleton to explain the core concept.Step 3: Introduce lazy initialization with synchronized method for thread safety.Step 4: Optimize with double-checked locking to reduce synchronization overhead.Step 5: Mention language-specific best practices like enum singleton in Java.

Time Allocation

Clarify: 2min → Approach: 5min → Code: 8min → Test & Discuss: 5min. Total ~20min

What the Interviewer Tests

Understanding of thread safety, synchronization, lazy initialization, and language-specific features; ability to optimize and explain tradeoffs.

Common Follow-ups

  • How to prevent cloning or reflection from creating multiple instances? → Use readResolve or throw exceptions.
  • How does volatile keyword help in double-checked locking? → Ensures visibility and prevents instruction reordering.
💡 These follow-ups test deeper understanding of thread safety and Java-specific pitfalls.
🔍
Pattern Recognition

When to Use

1. Need exactly one instance of a class globally. 2. Instance creation should be lazy or controlled. 3. Thread safety is required in concurrent environments. 4. Prevent multiple instantiations via cloning or serialization.

Signature Phrases

only one instanceglobal access pointthread-safe singletonlazy initialization

NOT This Pattern When

Static classes or global variables provide global access but do not control instantiation or lifecycle.

Similar Problems

Multiton Pattern - manages limited instances instead of oneFactory Pattern - controls object creation but not singletonDependency Injection - manages object lifecycles differently

Practice

(1/5)
1. In which scenario is applying the Liskov Substitution Principle (LSP) most critical to ensure system correctness?
easy
A. When a subclass adds new methods without overriding any superclass methods.
B. When a subclass uses composition instead of inheritance.
C. When a subclass narrows the input parameter types of an overridden method.
D. When a subclass extends a superclass but changes the expected behavior of inherited methods.

Solution

  1. Step 1: Understand LSP's core requirement

    LSP requires that subclasses can replace their superclasses without altering desirable properties of the program, especially behavior.
  2. Step 2: Analyze each option carefully

    When a subclass extends a superclass but changes the expected behavior of inherited methods. describes a subclass changing expected behavior, which violates LSP. When a subclass adds new methods without overriding any superclass methods. is safe as adding methods doesn't break substitutability. When a subclass narrows the input parameter types of an overridden method. narrows input types (contravariance violation), which breaks substitutability but is less direct than changing behavior. When a subclass uses composition instead of inheritance. is unrelated to LSP since composition is an alternative to inheritance.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Only changing inherited method behavior breaks LSP directly.
Hint: LSP is about preserving inherited behavior, not just adding features.
Common Mistakes:
  • Thinking adding methods breaks LSP
  • Confusing covariance and contravariance in parameters
  • Assuming composition relates directly to LSP
2. What is a key trade-off when using the Singleton pattern for managing the ParkingLot instance in a multi-level parking system?
medium
A. Singleton pattern automatically handles persistence of ParkingLot state across system restarts
B. Singleton ensures only one ParkingLot instance, which simplifies global access but limits scalability for multiple lots
C. Singleton improves concurrency by allowing multiple threads to create instances simultaneously
D. Singleton eliminates the need for synchronization in multi-threaded environments

Solution

  1. Step 1: Understand Singleton purpose

    Singleton restricts instantiation to one object, providing a global point of access.
  2. Step 2: Identify trade-offs

    While simplifying access, it limits flexibility and scalability, especially if multiple parking lots or levels need independent management.
  3. Step 3: Address misconceptions

    Singleton does not inherently improve concurrency or persistence, nor does it remove synchronization needs.
  4. Final Answer:

    Option B -> Option B
  5. Quick Check:

    Singleton simplifies access but restricts scalability [OK]
Hint: Singleton = one instance, good for global access but bad for scalability [OK]
Common Mistakes:
  • Believing Singleton improves concurrency or persistence
  • Assuming Singleton removes synchronization requirements
3. Which of the following statements about the Single Responsibility Principle is INCORRECT?
medium
A. SRP means a class should only have one method to ensure simplicity.
B. Applying SRP improves cohesion and reduces coupling.
C. A class should have only one reason to change, which means it should have only one responsibility.
D. Violating SRP can lead to fragile code that breaks when unrelated changes occur.

Solution

  1. Step 1: Analyze each statement

    A class should have only one reason to change, which means it should have only one responsibility. correctly states the core SRP definition.
  2. Step 2: Evaluate SRP means a class should only have one method to ensure simplicity.

    SRP is about reasons to change, not the number of methods; a class can have many methods if they serve one responsibility.
  3. Step 3: Confirm options A, B, and D

    Options A, B, and D are true: SRP improves cohesion, reduces coupling, and prevents fragile code.
  4. Final Answer:

    Option A -> Option A
  5. Quick Check:

    SRP ≠ one method per class; it's about one reason to change.
Hint: SRP is about reasons to change, not method count.
Common Mistakes:
  • Confusing responsibility with method count.
  • Assuming fewer methods always means better design.
  • Ignoring cohesion and coupling effects.
4. Examine the following buggy code implementing the Template Method Pattern. Which line contains the subtle bug that breaks the pattern's intended behavior?
medium
A. Line overriding prepare_recipe in Tea subclass
B. Line defining abstract method brew in base class
C. Line calling add_condiments inside prepare_recipe base method
D. Line overriding customer_wants_condiments in Tea subclass

Solution

  1. Step 1: Identify overridden methods

    Tea overrides prepare_recipe, which breaks the template method pattern by duplicating and changing the algorithm flow.
  2. Step 2: Understand impact

    Overriding the template method in subclass bypasses the base class skeleton, causing inconsistent behavior and code duplication.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Template method must not be overridden by subclasses [OK]
Hint: Overriding template method breaks algorithm skeleton [OK]
Common Mistakes:
  • Thinking overriding abstract methods is bug
  • Ignoring hook method usage
5. If the Composite pattern iterator is extended to allow reusing leaf components multiple times during traversal (e.g., shared leaves), which modification is necessary to ensure correct iteration without infinite loops?
hard
A. No change needed; the existing iterator handles reuse naturally.
B. Modify the iterator to push children in original order instead of reversed order.
C. Add a visited set to track and skip already visited components during iteration.
D. Convert the iterator to a recursive traversal to handle reuse correctly.

Solution

  1. Step 1: Understand reuse implications

    Reusing leaves means the same component can appear multiple times, risking infinite loops.
  2. Step 2: Identify solution to prevent infinite loops

    Tracking visited components prevents revisiting the same node repeatedly during iteration.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Visited set avoids infinite loops with shared components [OK]
Hint: Track visited nodes to handle shared components safely [OK]
Common Mistakes:
  • Assuming no changes needed
  • Changing push order does not fix reuse loops