← All patterns

Subsets

DFS enumeration of subsets, permutations, and combinations. Start-index for combinations; in-place swap for permutations; sort-and-skip for dedup on duplicate inputs.

8 problems 8 Medium

Enumerate every subset, permutation, or combination of an input. DFS with backtracking is the standard structure; only the branching policy differs. Subsets: include/exclude at each index (or iterative 'double' on each new element). Permutations: swap each remaining element into position. Combinations: pick from `start` onwards to avoid reorderings.

Duplicates are handled with sort + 'skip identical-to-previous at the same recursion level' — never globally, or you'll miss valid subsets where the duplicate is needed.

When to reach for this pattern

  • Output is all subsets, all permutations, or all combinations
  • Generate all valid expressions / configurations matching constraints
  • Enumerate decisions where each item is independently in/out
  • Letter case toggles, phone-number letter combinations

Canonical template

// subsets with dedup
sort(nums.begin(), nums.end());
vector<vector<int>> out;
vector<int> path;
function<void(int)> dfs = [&](int start) {
    out.push_back(path);
    for (int i = start; i < (int)nums.size(); ++i) {
        if (i > start && nums[i] == nums[i - 1]) continue;
        path.push_back(nums[i]);
        dfs(i + 1);
        path.pop_back();
    }
};
dfs(0);

C++ · adapt the names and types to your problem.

Common pitfalls

  • Skipping dedup logic on inputs with duplicates produces duplicate subsets
  • Forgetting path.pop_back() after recursion — corrupts subsequent branches
  • Pass-by-value path (no pop needed) vs pass-by-reference path (must pop) — pick one and stick to it
  • Combinations: passing i (reuse) vs i + 1 (no reuse) controls whether the same item is reusable

Related patterns

Problems (8)

Search ESC

Keyboard shortcuts

Shortcuts are disabled while typing in inputs.