recursion - Generating All Subsets of a Set Using Recursive Backtracking (Python) -
i'm trying understand backtracking i'm stuck in problem, here's prompt:
given set of distinct integers, return possible subsets.
example input: [1,2,3]
example output: [[], [1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]
here's code:
def subsets(nums): res = [] backtrack(res, [], nums, 0) return res def backtrack(res, temp, nums, start): # print(temp) res.append(temp) in range(start, len(nums)): temp.append(nums[i]) backtrack(res, temp, nums, + 1) temp.pop() # backtrack when return res list of empty lists of size 2^(len(nums)), right size numbers aren't there. printing temp before res.append(temp) shows temp carrying right output.
e.g.
res = [[], [], [], [], [], [], [], []]
print statements:
[] [1] [1, 2] [1, 2, 3] [1, 3] [2] [2, 3] [3]
why changes not carrying on res list?
edit 1:
this solution works, what's difference?
def subsets(nums): res = [] backtrack(res, [], nums, 0) return res def backtrack(res, temp, nums, start): # print(temp) res.append(temp) in range(start, len(nums)): backtrack(res, temp + [nums[i]], nums, + 1)
you're appending multiple references same list object res. can demonstrate doing
result = subsets([1, 2, 3]) print([id(u) u in result]) that print list of 8 identical ids.
so various changes make temp "lost", , final contents of res 8 references whatever final value of temp is, , in case it's empty list.
the simple way fix append copies of temp res.
def subsets(nums): res = [] backtrack(res, [], nums, 0) return res def backtrack(res, temp, nums, start): res.append(temp[:]) in range(start, len(nums)): temp.append(nums[i]) backtrack(res, temp, nums, + 1) temp.pop() # backtrack print(subsets([1, 2, 3])) output
[[], [1], [1, 2], [1, 2, 3], [1, 3], [2], [2, 3], [3]] fwiw, realise main point of exercise practice recursion, in python it's better avoid recursion unless need (eg, processing recursive data structures trees). here's more compact iterative solution.
def subsets(seq): z = [[]] x in seq: z += [y + [x] y in z] return z to see how works, can expand little, , add print call.
def subsets(seq): z = [[]] x in seq: print('z =', z, 'x =', x) w = [] y in z: w += [y + [x]] z += w return z result = subsets([1, 2, 3]) print(result) output
z = [[]] x = 1 z = [[], [1]] x = 2 z = [[], [1], [2], [1, 2]] x = 3 [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]] we start list z containing single empty list.
on each loop create new list w looping on z , making each item in w copy of corresponding item in z current x appended it. extend z contents of w.
just fun, here's iterative generator produces subsets (in natural order) bitstrings. method quite efficient, , it's if want subsets of large sequence without consuming lot of ram.
def subsets(seq): w = len(seq) in range(1<<w): yield [u u, v in zip(seq, reversed('{:0{}b}'.format(i, w))) if v=='1'] print(*subsets([1, 2, 3])) output
[] [1] [2] [1, 2] [3] [1, 3] [2, 3] [1, 2, 3]
Comments
Post a Comment