Facebook Pixel

2620. Counter

Problem Description

This problem asks you to create a function that generates a counter. The function createCounter takes an integer n as input and returns another function. This returned function acts as a counter that:

  1. Returns n when called for the first time
  2. Returns n + 1 when called the second time
  3. Returns n + 2 when called the third time
  4. Continues incrementing by 1 with each subsequent call

The key concept here is closure - the inner function maintains access to and can modify the variable from its outer scope. Each time you call the returned counter function, it remembers its previous value and increments from there.

For example, if you create a counter starting at 10:

  • First call returns 10
  • Second call returns 11
  • Third call returns 12
  • And so on...

The solution uses the post-increment operator i++ which returns the current value of i first, then increments it for the next call. This ensures the counter starts at n and increases by 1 each time it's invoked.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The problem requires a function that "remembers" its state between calls - specifically, it needs to remember what number to return next. This immediately points us toward using a closure.

Why closure? When we need a function to maintain state across multiple invocations, we can't use regular function parameters or local variables since they get reset with each call. Global variables would work but aren't clean or reusable. A closure elegantly solves this by allowing an inner function to access and modify variables from its outer function's scope, even after the outer function has finished executing.

The thought process goes like this:

  1. We need persistent state → closure can provide this
  2. We need to track the current value → store it in a variable in the outer function
  3. We need to increment after each call → use the post-increment operator i++

The post-increment operator i++ is perfect here because it does exactly what we need in one operation: returns the current value, then increments the variable for the next call. This is more concise than writing:

return i;
i = i + 1;

By initializing i with n and returning a function that uses i++, we create a self-contained counter that starts at n and automatically increments with each call. Each counter created by createCounter gets its own independent i variable, so multiple counters can exist without interfering with each other.

Solution Approach

The implementation uses JavaScript/TypeScript's closure mechanism to create a stateful counter function. Let's break down the solution step by step:

  1. Function Declaration: We define createCounter that accepts a number n as its parameter:

    function createCounter(n: number): () => number

    The return type () => number indicates this function returns another function that takes no parameters and returns a number.

  2. State Variable: Inside createCounter, we declare a local variable i and initialize it with the value of n:

    let i = n;

    This variable will serve as our counter's state, persisting between calls due to closure.

  3. Return the Counter Function: We return an anonymous function that captures the variable i from its parent scope:

    return function () {
        return i++;
    };
  4. Post-Increment Operation: The key operation i++ performs two actions:

    • First, it returns the current value of i
    • Then, it increments i by 1 for the next call

    This is different from pre-increment ++i, which would increment first and then return the new value.

How the Closure Works:

When createCounter(10) is called:

  • A new execution context is created with n = 10
  • Variable i is initialized to 10
  • The inner function is returned and keeps a reference to i
  • Even after createCounter finishes executing, the returned function maintains access to i

Each subsequent call to the returned counter function:

  • Accesses the same i variable
  • Returns its current value
  • Increments it for the next call

This pattern ensures each counter instance has its own independent state, allowing multiple counters to coexist without interference.

Ready to land your dream job?

Unlock your dream job with a 3-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through a concrete example where we create a counter starting at 5:

Step 1: Create the counter

const counter = createCounter(5);
  • When createCounter(5) executes, it creates a local variable i = 5
  • It returns a new function that has access to this i variable
  • The returned function is stored in counter

Step 2: First call to counter()

console.log(counter()); // Output: 5
  • The counter function executes return i++
  • Since i is currently 5, it returns 5
  • After returning, i is incremented to 6
  • The variable i persists in memory due to closure

Step 3: Second call to counter()

console.log(counter()); // Output: 6
  • The counter function executes return i++ again
  • Now i is 6 (from the previous increment)
  • It returns 6, then increments i to 7

Step 4: Third call to counter()

console.log(counter()); // Output: 7
  • The function accesses the same i variable (now 7)
  • Returns 7, increments to 8

Creating Multiple Independent Counters:

const counter1 = createCounter(10);
const counter2 = createCounter(100);

console.log(counter1()); // Output: 10
console.log(counter2()); // Output: 100
console.log(counter1()); // Output: 11
console.log(counter2()); // Output: 101

Each counter maintains its own separate i variable through closure, so they operate independently without affecting each other.

Solution Implementation

1def createCounter(n: int):
2    """
3    Creates a counter function that starts from a given number
4    and increments by 1 each time it's called
5  
6    Args:
7        n: The initial value of the counter
8  
9    Returns:
10        A function that returns the current counter value and then increments it
11    """
12    # Store the initial value in a closure variable
13    current_value = n
14  
15    def counter():
16        """
17        Inner function that captures the current_value variable
18        Returns the current value and then increments it (post-increment)
19        """
20        nonlocal current_value  # Declare that we're modifying the outer scope variable
21      
22        # Store the current value to return it
23        result = current_value
24        # Increment the counter for the next call
25        current_value += 1
26        # Return the value before increment
27        return result
28  
29    # Return the counter function
30    return counter
31
32
33# Usage example:
34# counter = createCounter(10)
35# print(counter())  # 10
36# print(counter())  # 11
37# print(counter())  # 12
38
1/**
2 * Interface representing a counter function that returns an integer
3 */
4@FunctionalInterface
5interface Counter {
6    int call();
7}
8
9/**
10 * Solution class containing the createCounter method
11 */
12class Solution {
13    /**
14     * Creates a counter function that starts from a given number
15     * and increments by 1 each time it's called
16     * @param n - The initial value of the counter
17     * @return A Counter function that returns the current counter value and then increments it
18     */
19    public Counter createCounter(int n) {
20        // Use an array to store the value (workaround for Java's requirement that 
21        // variables used in lambda expressions must be final or effectively final)
22        final int[] currentValue = {n};
23      
24        // Return a lambda function that captures the currentValue array
25        return () -> {
26            // Return the current value and then increment it (post-increment)
27            return currentValue[0]++;
28        };
29    }
30  
31    /**
32     * Usage example:
33     * Solution solution = new Solution();
34     * Counter counter = solution.createCounter(10);
35     * counter.call(); // 10
36     * counter.call(); // 11
37     * counter.call(); // 12
38     */
39}
40
1#include <functional>
2
3/**
4 * Creates a counter function that starts from a given number
5 * and increments by 1 each time it's called
6 * @param n - The initial value of the counter
7 * @returns A function that returns the current counter value and then increments it
8 */
9std::function<int()> createCounter(int n) {
10    // Return a lambda function that captures n by value and makes it mutable
11    // The mutable keyword allows modification of captured variables
12    return [n]() mutable -> int {
13        // Return the current value and then increment it (post-increment)
14        return n++;
15    };
16}
17
18/**
19 * Usage example:
20 * auto counter = createCounter(10);
21 * counter(); // 10
22 * counter(); // 11
23 * counter(); // 12
24 */
25
1/**
2 * Creates a counter function that starts from a given number
3 * and increments by 1 each time it's called
4 * @param n - The initial value of the counter
5 * @returns A function that returns the current counter value and then increments it
6 */
7function createCounter(n: number): () => number {
8    // Store the initial value in a closure variable
9    let currentValue: number = n;
10  
11    // Return a function that captures the currentValue variable
12    return function(): number {
13        // Return the current value and then increment it (post-increment)
14        return currentValue++;
15    };
16}
17
18/**
19 * Usage example:
20 * const counter = createCounter(10)
21 * counter() // 10
22 * counter() // 11
23 * counter() // 12
24 */
25

Time and Space Complexity

Time Complexity: O(1)

  • The createCounter function itself executes in constant time, performing only variable initialization and returning a function reference.
  • Each call to the returned counter function executes in constant time, as it only performs a single increment operation and returns a value.

Space Complexity: O(1)

  • The createCounter function creates a closure that captures a single variable i of primitive type number.
  • The returned function maintains a reference to this single variable through the closure scope.
  • No additional data structures or recursive calls are involved, resulting in constant space usage regardless of how many times the counter is called.

Common Pitfalls

1. Using a Simple Variable Instead of Closure

A common mistake is trying to use a global variable or passing the counter value directly without closure:

Incorrect Approach:

def createCounter(n: int):
    def counter():
        return n
        n += 1  # This will cause an UnboundLocalError
    return counter

Problem: Python treats n as a local variable when you try to modify it with n += 1, causing an UnboundLocalError because it's referenced before assignment in the local scope.

Solution: Use the nonlocal keyword to explicitly declare that you're modifying the outer scope variable:

def createCounter(n: int):
    def counter():
        nonlocal n
        result = n
        n += 1
        return result
    return counter

2. Confusing Pre-increment with Post-increment Behavior

In languages like JavaScript/TypeScript, using ++i instead of i++ would cause the counter to start at n+1 instead of n:

Incorrect:

function createCounter(n) {
    let i = n;
    return function() {
        return ++i;  // Returns n+1 on first call
    };
}

Correct:

function createCounter(n) {
    let i = n;
    return function() {
        return i++;  // Returns n on first call
    };
}

3. Using Mutable Default Arguments in Python

When creating multiple counters, avoid using mutable default arguments:

Incorrect:

def createCounter(n: int, state=[]):
    if not state:
        state.append(n)
  
    def counter():
        result = state[0]
        state[0] += 1
        return result
  
    return counter

Problem: The mutable default argument state=[] is shared across all function calls, causing different counter instances to interfere with each other.

Solution: Use closure variables or create new instances for each counter:

def createCounter(n: int):
    state = [n]  # Create a new list for each counter instance
  
    def counter():
        result = state[0]
        state[0] += 1
        return result
  
    return counter

4. Forgetting to Return the Inner Function

A beginner mistake is calling the inner function instead of returning it:

Incorrect:

def createCounter(n: int):
    current_value = n
  
    def counter():
        nonlocal current_value
        result = current_value
        current_value += 1
        return result
  
    return counter()  # Wrong! This returns the result of calling counter, not the function itself

Correct:

def createCounter(n: int):
    current_value = n
  
    def counter():
        nonlocal current_value
        result = current_value
        current_value += 1
        return result
  
    return counter  # Return the function object, not its result

5. Not Understanding Closure Scope in Loops

When creating multiple counters in a loop, be careful about variable scope:

Incorrect:

counters = []
for i in range(3):
    def counter():
        return i  # All counters will return the final value of i (2)
    counters.append(counter)

Solution: Create a proper closure for each iteration:

counters = []
for i in range(3):
    def make_counter(start):
        value = start
        def counter():
            nonlocal value
            result = value
            value += 1
            return result
        return counter
    counters.append(make_counter(i))
Discover Your Strengths and Weaknesses: Take Our 3-Minute Quiz to Tailor Your Study Plan:

Which algorithm is best for finding the shortest distance between two points in an unweighted graph?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More