Weekly Coding Challenge #1: Solving Subsets II with Backtracking
- 24 Jul 2025

I've decided to do a new blog series where I’ll be sharing coding challenges I’ve solved each week. For our first entry, I’ll walk through the classic Subsets II problem, which involves returning all possible unique subsets in an integer array that may contain duplicates, demonstrating how to approach it, step by step, using one of the most fundamental algorithmic techniques: backtracking.
Problem Overview
Here’s the problem statement:
You are given an array nums of integers, which may contain duplicates. Return all possible subsets.
The solution must not contain duplicate subsets. You may return the solution in any order.
You can also find a more detailed problem statement here.
The goal is to produce every possible subset from the input array, while ensuring that no duplicate subsets are included in the output. This is a common scenario when dealing with arrays that can have repeated elements.
1. Understanding Backtracking
Before diving into the implementation, it’s important to clarify what backtracking is and why it fits this problem.
Backtracking is an algorithmic approach often used for searching through all possible decisions in a sequence, systematically exploring all configurations and undoing ('backtracking') steps as necessary. It’s particularly effective for generating all possible combinations or permutations.
In the context of Subsets II, backtracking enables us to explore every possible way to build a subset, one element at a time, and carefully manage the inclusion of duplicates.
2. TypeScript Solution
Let’s look at the core implementation:
/**
* Given an integer array nums that may contain duplicates, return all possible subsets (the power set).
* The solution set must not contain duplicate subsets. Return the solution in any order.
*/
const subsetsWithDup = (nums: number[]) => {
const backtrack = (start: number, subset: number[], nums: number[], res: number[][]) => {
res.push([...subset]);
for (let i = start; i < nums.length; i++) {
// Skip duplicates
if (i > start && nums[i] === nums[i - 1]) {
continue;
}
subset.push(nums[i]);
backtrack(i + 1, subset, nums, res);
subset.pop();
}
};
const res: number[][] = [];
nums.sort((a: number, b: number) => a - b);
backtrack(0, [], nums, res);
return res;
};
console.log(subsetsWithDup([1, 2, 2]));
3. Step-By-Step Explanation
Let’s break down the solution, focusing on each step and decision.
a) Sorting the Input
nums.sort((a: number, b: number) => a - b);
The array is sorted first. This is essential for detecting duplicates efficiently. If duplicate numbers are adjacent, it’s much easier to skip them during subset generation.
b) The Backtracking Function
const backtrack = (start: number, subset: number[], nums: number[], res: number[][]) => { ... }
This function explores all possible subset combinations from a given start index in nums
. Here’s what happens inside:
-
Add Current Subset:
At each stage, add a copy of the current subset to the result list:res.push([...subset]);
-
Iterate From Start Index:
For each possible next element (starting from the current index), we consider two options: include or skip. -
Skip Duplicates:
The key line that avoids duplicate subsets:if (i > start && nums[i] === nums[i - 1]) { continue; }
This ensures that, from the same decision point, we don’t select the same value twice.
-
Include Element, Explore Further:
We add the current element, proceed to the next index, and then remove the element ('backtrack') for subsequent branches:subset.push(nums[i]); backtrack(i + 1, subset, nums, res); subset.pop();
c) Generating Results
The process starts with an empty subset and fills the res
array with every unique subset generated through the backtracking process.
4. Example
Given this input:
subsetsWithDup([1, 2, 2]);
The output will be:
[
[],
[1],
[1, 2],
[1, 2, 2],
[2],
[2, 2]
]
Each subset is unique, and all possible combinations are present.
Conclusion
By applying backtracking and carefully managing duplicate handling using sorting and an early-skip condition, we can efficiently generate all unique subsets of an array with duplicates. This approach is both scalable and easy to implement, making it a strong fit for this class of problems.
If you have any questions, suggestions, or feedback, feel free to leave a comment. Stay tuned for next week’s challenge!