Given an integer array nums
of unique elements, return all possible subsets (the power set).
The solution set must not contain duplicate subsets. Return the solution in any order.
For example:
nums = [1,2,3]
Output: [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
nums = [0]
Output: [[],[0]]
Constraints:
1 <= nums.length <= 10
-10 <= nums[i] <= 10
nums
are unique.## Subsets (Power Set) - LeetCode Problem
This problem asks us to generate all possible subsets (the power set) of a given array of unique integers. The solution set must not contain duplicate subsets, and the order of the subsets doesn't matter.
### 1. Brute Force Approach
The simplest approach is to iterate through all possible combinations of elements in the input array. We can do this by generating all binary numbers from 0 to 2^n - 1, where n is the number of elements in the input array. Each bit in the binary number represents whether the corresponding element in the array is present in the current subset.
```python
def subsets_brute_force(nums):
n = len(nums)
result = []
for i in range(2**n):
subset = []
for j in range(n):
if (i >> j) & 1:
subset.append(nums[j])
result.append(subset)
return result
# Example usage:
nums = [1, 2, 3]
print(subsets_brute_force(nums))
Explanation:
A more efficient approach is to use backtracking. We can build subsets recursively. At each step, we have a choice: either include the current element in the subset or exclude it. This leads to a tree-like exploration of all possible subsets.
def subsets_backtracking(nums):
result = []
n = len(nums)
def backtrack(index, current_subset):
result.append(current_subset[:]) # Add a copy to avoid modification
for i in range(index, n):
current_subset.append(nums[i])
backtrack(i + 1, current_subset)
current_subset.pop() # Backtrack: remove the last element
backtrack(0, [])
return result
# Example usage:
nums = [1, 2, 3]
print(subsets_backtracking(nums))
Explanation:
backtrack
function recursively explores all possible subsets.index
in the input array.result
.index
to the end of the array, it includes the element in the current_subset
, recursively calls backtrack
to explore further subsets, and then removes the element (backtracks) to explore subsets without that element.The time complexity of the backtracking solution is O(N * 2^N), where N is the number of elements in the input array nums
. Here's why:
backtrack
function, result.append(current_subset[:])
takes O(N) time because it creates a copy of the current_subset
. We need to copy it because the list is passed by reference and we don't want to keep the reference to the current subset around.Therefore, the overall time complexity is O(N * 2^N).
The space complexity of the backtracking solution is O(N), excluding the space used to store the output subsets.
current_subset
list will, at most, store N elements.Output Space: The space to store all the subsets is O(N * 2^N), but this is typically not considered for the space complexity analysis (we don't count output space complexity).
Therefore, the auxiliary space complexity (excluding the output) is O(N).
[[]]
. Both brute force and backtracking solutions correctly handle this case.Here's an example of how we might handle duplicates (although the problem states there won't be any):
def subsets_with_duplicates(nums):
result = []
nums.sort()
n = len(nums)
def backtrack(index, current_subset):
result.append(current_subset[:])
for i in range(index, n):
if i > index and nums[i] == nums[i-1]:
continue # Skip duplicate elements
current_subset.append(nums[i])
backtrack(i + 1, current_subset)
current_subset.pop()
backtrack(0, [])
return result