2026-08-25 19:14:07 -06:00

212 lines
4.6 KiB
Markdown

---
layout: page
title: Subsets (Backtracking)
last_solved: 2020-06-22
category: recursion, backtracking
leetcode_url: https://leetcode.com/problems/subsets/
status: Solved
---
Problem
-------
```
Given a set of distinct integers, nums, return all possible subsets (the power set).
Note: The solution set must not contain duplicate subsets.
Example:
Input: nums = [1,2,3]
Output:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
```
Solution
----------
All backtracking problems have this structure, just memorize it.
Still not sure why we +1 to index and why that is different from Permutation. This series of articles tries to explain it.
[part 1](https://medium.com/algorithms-and-leetcode/backtracking-e001561b9f28)
[part 2](https://medium.com/algorithms-and-leetcode/backtracking-with-leetcode-problems-part-2-705c9cc70e52)
[part 3](https://medium.com/algorithms-and-leetcode/in-depth-backtracking-with-leetcode-problems-part-3-b225f19e0d51)
{% highlight python %}
def subsets3(nums):
def backtrack(currentSubset, allSubsets, nums, index):
allSubsets.append( currentSubset.copy() )
for i in range(index, len(nums)):
currentSubset.append(nums[i])
print(currentSubset)
backtrack( currentSubset, allSubsets, nums, i+1 )
currentSubset.pop()
print(currentSubset)
ans = []
backtrack([], ans, nums, 0)
return ans
{% endhighlight %}
printing the currentSubset at each iteration looks like this:
```
[1]
[1, 2]
[1, 2, 3]
[1, 2]
[1]
[1, 3]
[1]
[]
[2]
[2, 3]
[2]
[]
[3]
[]
[[], [1], [1, 2], [1, 2, 3], [1, 3], [2], [2, 3], [3]]
```
![image1](https://miro.medium.com/max/1400/1*xrjS6JIZ5f7wFCNBDPrr0g.png)
![image1](https://miro.medium.com/max/1400/1*_s5iiwdZXbg1OFWO9YDjng@2x.jpeg)
______________
Compare these two solutions:
{% highlight python %}
def subsets5(nums):
def helper(start, currentSubset, allSubsets):
output.append( currentSubset.copy() )
for i in range(start, len(nums) ):
currentSubset.append( nums[i] )
helper(i+1, currentSubset, output)
currentSubset.pop()
output = []
helper(0, [], output)
return output
'''
recursion without backtracking from timonthy chang
https://www.youtube.com/watch?v=Mi_C_CMW7vQ
'''
def subsets4(nums):
output = []
def helper(start, currentSubset, output):
# output += [tmp]
output.append(currentSubset)
for i in range(start, len(nums)):
print( (i+1, currentSubset+[nums[i]]) )
helper( i+1, currentSubset+[nums[i]], output )
helper(0, [], output)
return output
{% endhighlight %}
The output is like this:
```
(1, [1])
(2, [1, 2])
(3, [1, 2, 3])
(3, [1, 3])
(2, [2])
(3, [2, 3])
(3, [3])
[[], [1], [1, 2], [1, 2, 3], [1, 3], [2], [2, 3], [3]]
[[], [1], [1, 2], [1, 2, 3], [1, 3], [2], [2, 3], [3]]
```
____________
![image1](https://miro.medium.com/max/1050/1*ddhF2JWfmEl8yLwjx5vt7Q.jpeg)
______________
![image1](https://5wlqpa.dm.files.1drv.com/y4mWw6FM6vfQ2uGgQLZVTXK03b2a4oZzG94ARUypRFP8T48s5todh08mGzzH5CVx79cVUGI-lKe00r0vgEJt0PlTTYmYze-M_EXdkfEaUTggaMMsCwXXKXHUC3ko0ITL_jl14nHjNEXlI5I3kh3AnD98MerAvWU3GuICbnIDQETihjZo-F86GzUuLYTn-2Q-ZoddrY1zu3b6rchFalBW9mJEQ?width=2425&height=1523&cropmode=none)
![image1](https://5wjpha.dm.files.1drv.com/y4mECUr_-JYl8Sn_JLbFcKa5QKYMklb32Cht5rZj3MsoCjcLrnWDDaxHqFCOwIh2VD5UT5xoy2xcKKpoMAvYe4-kH0xVw8vdaEkGRva0OF1WdfmvoPifSLQLOK4RAGPO72WQifQ87qsF8APOnzvPA3M5LAhp7wvYU8X7f__vZO7Oae4ZVj0dARrF8fms6KVQ__ect74q1YyqECYIjJci7DQkQ?width=2041&height=1334&cropmode=none)
_______________
Another way is the BFS approach from [educative](https://www.educative.io/courses/grokking-the-coding-interview/gx2OqlvEnWG)
```
Given set: [1, 5, 3]
Start with an empty set: [[]]
Add the first number (1) to all the existing subsets to create new subsets: [[], [1]];
Add the second number (5) to all the existing subsets: [[], [1], [5], [1,5]];
Add the third number (3) to all the existing subsets: [[], [1], [5], [1,5], [3], [1,3], [5,3], [1,5,3]].
```
{% highlight python %}
def find_subsets(nums):
subsets = []
# start by adding the empty subset
subsets.append([])
for currentNumber in nums:
# we will take all existing subsets and insert the current number in them to create new subsets
n = len(subsets)
for i in range(n):
# create a new subset from the existing subset and insert the current element to it
set = list(subsets[i])
set.append(currentNumber)
subsets.append(set)
return subsets
{% endhighlight %}
Time and space complexity is O(2^n) because we will have 2^n items