An interactive visualization of the backtracking algorithm to generate all possible subsets. Watch the decision tree grow as we explore include/exclude choices for each element.
Backtracking LeetCode 78 โ Mediumnums of unique elements, return all possible subsets (the power set).nums = [1,2,3][[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
fun subsets(nums: IntArray): List<List<Int>> { val result = mutableListOf<List<Int>>() fun backtrack(start: Int, current: MutableList<Int>) { result.add(current.toList()) for (i in start until nums.size) { current.add(nums[i]) // include backtrack(i + 1, current) current.removeAt(current.size - 1) // backtrack } } backtrack(0, mutableListOf()) return result}
The backtracking approach explores all possible combinations by making a sequence of choices. For each element, we have two options: include it or skip it. The decision tree visualizes this: each level represents a decision for one element, and each path from root to leaf represents one subset.
start to the end of the array:
nums[i] to the current subsetbacktrack(i + 1, current) to explore all subsets that include this element
The algorithm systematically explores every possible subset by treating subset generation as a series of binary decisions (include or exclude).
The start parameter ensures we don't revisit earlier elements, avoiding duplicates.
By adding the current subset before the loop, we capture every state of the subset as we build it, including the empty set and all partial subsets.
There are 2n possible subsets for an array of size n.
Each subset takes O(n) time to copy into the result.
The recursion depth is at most n, requiring O(n) stack space.