Talentd
FleetCode
Make and follow sheets.Sign in

Iterator for Combination solution and explanation

MediumBacktrackingDesignIteratorString5 min read72.7% acceptanceUpdated 9 Apr 2026
Iterator for combination | BitMasking | Backtracking | Leetcode #1286Techdose · 23:43 · 4K viewsWatch on YouTube
9 more videos on this problem
  1. Iterator for combination | BitMasking | Backtracking | Leetcode #1286Techdose · 23:43 · 4K views
  2. Iterator for Combination | LeetCode 1286 | C++, Java, PythonKnowledge Center · 24:03 · 4K views
  3. iterator for combination leetcode | leetcode 1286 | generate with queueNaresh Gupta · 9:37 · 1K views
  4. Leetcode 1286: Iterator for CombinationAlgorithms Casts · 18:04 · 946 views
  5. Iterator for Combination | Leetcode 1286 | Live coding session 🔥🔥🔥 | BacktrackingCoding Decoded · 6:10 · 866 views
  6. Iterator for Combination | Bit Mask | Day 13 | [ August LeetCoding Challenge ] [ Leetcode #1286 ]Algorithms Made Easy · 5:34 · 498 views
  7. Leetcode - Iterator for Combination (Python)Timothy H Chang · 8:04 · 426 views
  8. Iterator for Combination | Leet code 1286 | Theory explained + Python codeSai Anish Malla · 12:58 · 314 views
  9. 1286. Iterator for Combination LeetCode | BitMasking | PriorityQueueCoding Gist · 10:22 · 299 views
  10. LeetCode 1286. Iterator for CombinationHappy Coding · 30:08 · 209 views

The problem

Design the CombinationIterator class:

  • CombinationIterator(string characters, int combinationLength) Initializes the object with a string characters of sorted distinct lowercase English letters and a number combinationLength as arguments.
  • next() Returns the next combination of length combinationLength in lexicographical order.
  • hasNext() Returns true if and only if there exists a next combination.

Example 1:

Input
["CombinationIterator", "next", "hasNext", "next", "hasNext", "next", "hasNext"]
[["abc", 2], [], [], [], [], [], []]
Output
[null, "ab", true, "ac", true, "bc", false]

Explanation
CombinationIterator itr = new CombinationIterator("abc", 2);
itr.next();    // return "ab"
itr.hasNext(); // return True
itr.next();    // return "ac"
itr.hasNext(); // return True
itr.next();    // return "bc"
itr.hasNext(); // return False

Constraints:

  • 1 <= combinationLength <= characters.length <= 15
  • All the characters of characters are unique.
  • At most 104 calls will be made to next and hasNext.
  • It is guaranteed that all calls of the function next are valid.

Approach overview

Problem Overview: Design an iterator that returns all combinations of length k from a given sorted string of characters. Each call to next() should return the next combination in lexicographical order, and hasNext() should indicate whether more combinations remain.

Approach 1: Precompute All Combinations (Time: O(C(n,k) * k), Space: O(C(n,k) * k))

This approach generates every valid combination during initialization using backtracking. Start from index 0, recursively build a string by choosing the next character and continuing until the length reaches k. Each completed combination is appended to a list. Because the input string is already sorted, the generated combinations naturally appear in lexicographic order. The iterator then simply maintains an index pointer: next() returns the current element and increments the pointer, while hasNext() checks whether the pointer is within bounds.

The main advantage is simplicity. Once the combinations are precomputed, each iterator call is constant time. The tradeoff is memory usage because all C(n,k) combinations are stored upfront.

Approach 2: Generate Combinations on the Fly (Time: O(C(n,k) * k), Space: O(k))

This approach generates the next combination only when needed instead of storing all results. Maintain an array of indices representing the current combination. Initially it contains [0,1,2,...,k-1]. When next() is called, build the string using those indices from the original characters.

To compute the next state, scan the indices from right to left and find the first position that can be incremented without exceeding its limit. Increase that index and reset all positions to its right to the smallest valid increasing sequence. This logic is similar to generating the next lexicographical combination and works well with an iterator design pattern. Only the current index array is stored, so the memory footprint stays small.

This technique avoids storing every combination and is typically preferred when the number of combinations is large. The time cost shifts from initialization to each call to next(), but each step still runs in about O(k).

Recommended for interviews: Interviewers usually expect the on‑the‑fly generation approach because it demonstrates understanding of string combination generation and iterator state management. Implementing the precomputation method first is still valuable because it proves you understand how combinations are formed. The optimized iterator version shows stronger design and algorithmic reasoning.

Approach 1: Precompute All Combinations

In this approach, we precompute all the combinations of the given string of a specified length. This allows us to provide the next combination in constant time by just iterating over the precomputed list. For this, we can use recursion or libraries to generate combinations initially and store them in an internal data structure.

To find all combinations of a particular length, you can use backtracking or an iterative process that resembles a binary-like increase in combinations selection.

from itertools import combinations

class CombinationIterator:
    def __init__(self, characters: str, combinationLength: int):
        self.combinations = list(combinations(characters, combinationLength))
        self.index = 0

    def next(self) -> str:
        comb = self.combinations[self.index]
        self.index += 1
        return ''.join(comb)

    def hasNext(self) -> bool:
        return self.index < len(self.combinations)
#include <vector>
#include <string>
#include <algorithm>

class CombinationIterator {
    std::vector<std::string> combinations;
    size_t index;

    void generate(const std::string& str, int combinationLength) {
        std::string combination;
        generateCombinations(str, combinationLength, 0, combination);
    }

    void generateCombinations(const std::string& str, int length, int start, std::string& combination) {
        if (length == 0) {
            combinations.push_back(combination);
            return;
        }
        for (int i = start; i <= str.size() - length; ++i) {
            combination.push_back(str[i]);
            generateCombinations(str, length - 1, i + 1, combination);
            combination.pop_back();
        }
    }

public:
    CombinationIterator(std::string characters, int combinationLength) : index(0) {
        generate(characters, combinationLength);
    }

    std::string next() {
        return combinations[index++];
    }

    bool hasNext() {
        return index < combinations.size();
    }
};

This Python solution uses the itertools.combinations library to generate all the combinations of the given length at the initialization stage. Whenever next() is called, it returns the current combination and advances the index.

Complexity

Time Complexity: O(n!) for precomputation, O(1) for next and hasNext.
Space Complexity: O(n!) due to storage of combinations.

Try this approach in the editor

Approach 2: Generate Combinations on The Fly

Instead of generating all combinations at once, we can generate them on the fly when next() is called. This approach uses bit manipulation to generate the combination efficiently by representing each combination as a bitmask. However, this requires understanding how to generate valid combinations incrementally with proper bit manipulation.

class CombinationIterator {
    constructor(characters, combinationLength) {
        this.characters = characters;
        this.combinationLength = combinationLength;
        this.combinations = [];
        this.currentIndex = 0;
        this._generateCombinations('', 0);
    }

    _generateCombinations(prefix, start) {
        if (prefix.length === this.combinationLength) {
            this.combinations.push(prefix);
            return;
        }
        for (let i = start; i < this.characters.length; i++) {
            this._generateCombinations(prefix + this.characters[i], i + 1);
        }
    }

    next() {
        return this.combinations[this.currentIndex++];
    }

    hasNext() {
        return this.currentIndex < this.combinations.length;
    }
}
public class CombinationIterator {
    private string characters;
    private int combinationLength;
    private int[] indices;
    private bool hasCombination;

    public CombinationIterator(string characters, int combinationLength) {
        this.characters = characters;
        this.combinationLength = combinationLength;
        this.indices = new int[combinationLength];
        for (int i = 0; i < combinationLength; i++) {
            indices[i] = i;
        }
        hasCombination = true;
    }

    public string Next() {
        if (!hasCombination) return null;
        char[] combination = new char[combinationLength];
        for (int i = 0; i < combinationLength; i++) {
            combination[i] = characters[indices[i]];
        }
        getNextIndices();
        return new string(combination);
    }

    private void getNextIndices() {
        int n = characters.Length;
        for (int i = combinationLength - 1; i >= 0; i--) {
            if (indices[i] != i + n - combinationLength) {
                indices[i]++;
                for (int j = i + 1; j < combinationLength; j++) {
                    indices[j] = indices[j - 1] + 1;
                }
                return;
            }
        }
        hasCombination = false;
    }

    public bool HasNext() {
        return hasCombination;
    }
}

This JavaScript solution generates combinations during the initialization phase using a depth-first search approach. The _generateCombinations method is used to recursively create all combinations. The next method fetches the combinations sequentially from the precomputed list.

Complexity

Time Complexity: O(n!) for precomputation, O(1) for next and hasNext.
Space Complexity: O(n!) due to the storage of combinations.

Try this approach in the editor

Approach 3: Default Approach

class CombinationIterator {
    private int n;
    private int combinationLength;
    private String characters;
    private StringBuilder t = new StringBuilder();
    private List<String> cs = new ArrayList<>();
    private int idx = 0;

    public CombinationIterator(String characters, int combinationLength) {
        n = characters.length();
        this.combinationLength = combinationLength;
        this.characters = characters;
        dfs(0);
    }

    public String next() {
        return cs.get(idx++);
    }

    public boolean hasNext() {
        return idx < cs.size();
    }

    private void dfs(int i) {
        if (t.length() == combinationLength) {
            cs.add(t.toString());
            return;
        }
        if (i == n) {
            return;
        }
        t.append(characters.charAt(i));
        dfs(i + 1);
        t.deleteCharAt(t.length() - 1);
        dfs(i + 1);
    }
}

/**
 * Your CombinationIterator object will be instantiated and called as such:
 * CombinationIterator obj = new CombinationIterator(characters, combinationLength);
 * String param_1 = obj.next();
 * boolean param_2 = obj.hasNext();
 */
type CombinationIterator struct {
	cs  []string
	idx int
}

func Constructor(characters string, combinationLength int) CombinationIterator {
	t := []byte{}
	n := len(characters)
	cs := []string{}
	var dfs func(int)
	dfs = func(i int) {
		if len(t) == combinationLength {
			cs = append(cs, string(t))
			return
		}
		if i == n {
			return
		}
		t = append(t, characters[i])
		dfs(i + 1)
		t = t[:len(t)-1]
		dfs(i + 1)
	}
	dfs(0)
	return CombinationIterator{cs, 0}
}

func (this *CombinationIterator) Next() string {
	ans := this.cs[this.idx]
	this.idx++
	return ans
}

func (this *CombinationIterator) HasNext() bool {
	return this.idx < len(this.cs)
}

/**
 * Your CombinationIterator object will be instantiated and called as such:
 * obj := Constructor(characters, combinationLength);
 * param_1 := obj.Next();
 * param_2 := obj.HasNext();
 */
Try this approach in the editor

Complexity comparison

ApproachComplexity
Precompute All Combinations

Time Complexity: O(n!) for precomputation, O(1) for next and hasNext.
Space Complexity: O(n!) due to storage of combinations.

Generate Combinations on The Fly

Time Complexity: O(n!) for precomputation, O(1) for next and hasNext.
Space Complexity: O(n!) due to the storage of combinations.

Default Approach–

Complexity analysis

ApproachTimeSpaceWhen to Use
Precompute All CombinationsO(C(n,k) * k)O(C(n,k) * k)When simplicity matters and memory is not a constraint
Generate Combinations on the FlyO(C(n,k) * k)O(k)When the number of combinations is large and memory should remain minimal

Frequently asked questions

Is Iterator for Combination easy or hard?

Iterator for Combination is rated Medium because it combines combination generation with object-oriented iterator design. The logic for computing the next lexicographic combination requires careful index manipulation.

Iterator for Combination Python/Java solution

In Python, combinations are often generated using backtracking with a list storing all results or with an index pointer for on-demand generation. Java implementations typically store indices in an int array and update them lexicographically to produce the next combination string.

How to solve Iterator for Combination in O(n)?

The full problem cannot be solved in O(n) overall because the iterator must eventually produce C(n,k) combinations. However, each call to next() can run in about O(k) time by updating the combination indices and rebuilding the string from the original characters.

What is the best approach for Iterator for Combination?

The most practical approach is generating combinations on the fly using a lexicographical index array. It stores only the current combination indices and updates them to produce the next combination. This keeps space complexity at O(k) while still generating all C(n,k) combinations in order.

Is Iterator for Combination asked at Google/Amazon/Meta?

Iterator and design-style problems like this frequently appear in interviews at large tech companies including Google, Amazon, and Meta. They test understanding of iterator patterns, combination generation, and maintaining internal state between calls.

What data structure is used in Iterator for Combination?

Most implementations use an array or list of indices to represent the current combination. Backtracking or iterative index updates generate the next combination while preserving lexicographic order.

What is the time complexity of Iterator for Combination?

Generating all combinations requires O(C(n,k) * k) time because each combination of length k must be constructed. In the precomputation approach this cost occurs during initialization, while in the iterator approach it is distributed across calls to next().

Comments

Now write it yourselfClose this page and solve Iterator for Combination in the editor, without looking.
Practise Iterator for Combination