Intuition
Each element makes one binary choice: in or out. Recurse on both branches carrying the running sum; the leaves of that decision tree are exactly the 2ⁿ subset sums.
The purest take-or-skip recursion: at every index there are exactly two branches, and the leaves are the 2^n outcomes. Whenever each element independently is or isn't included, this binary tree is the search space — no used array and no loop, just two calls. Subsets and subset-sum-equals-target are the same tree with different bookkeeping.
Approach
The decision tree
At index i with running sum s, branch to (i+1, s + a[i]) and (i+1, s). Depth n, 2ⁿ leaves.
Collect at the base
When i == n the running sum is one subset's total — append it.
Iterative alternative
Start with [0]; for each element, extend the list with every existing sum + element. Same doubling, no recursion.
Solution & live demo
Common pitfalls
Recursing from a loop as if it were a combination problem
for j in range(i, len(nums)):
go(j + 1, s + nums[j])go(i + 1, s + nums[i]) # take go(i + 1, s) # skip
The loop form can be made to work, but it obscures the structure and makes the base case awkward. Take-or-skip states the actual decision — each element is in or out — and each element is visited exactly once per path.
Appending the sum before reaching the end
def go(i, s):
res.append(s)
if i == len(nums): returndef go(i, s):
if i == len(nums):
res.append(s)
returnRecording at every node collects partial sums from halfway down the tree, producing far more than 2^n entries. Only leaves — where every element has been decided — represent complete subsets.
Forgetting to sort the result
return res
return sorted(res)
GFG expects the sums in non-decreasing order, but the recursion emits them in take-first order. The values are right; the sequence isn't.
Edge cases
One subset — the empty one, sum 0.
Sums repeat legitimately; the answer keeps duplicates.