我试图理解回溯,但我遇到了这个问题,这里有提示:
给定一组不同的整数,返回所有可能的子集。
示例输入:[1,2,3]
示例输出:[[], [1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]
这是我的代码:
def subsets(nums):
res = []
backtrack(res, [], nums, 0)
return res
def backtrack(res, temp, nums, start):
# print(temp)
res.append(temp)
for i in range(start, len(nums)):
temp.append(nums[i])
backtrack(res, temp, nums, i + 1)
temp.pop() # Backtrack
当我返回res
时,我会收到一个大小为2^(len(nums))
的空列表的列表,这是正确的大小,但数字不在那里。但是,在temp
之前打印res.append(temp)
表示temp正在输出正确的输出。
E.g。
res = [[], [], [], [], [], [], [], []]
打印声明:
[] [1] [1, 2] [1, 2, 3] [1, 3] [2] [2, 3] [3]
为什么更改没有转移到res
列表?
编辑1:
这个解决方案有效,有什么区别?
def subsets(nums):
res = []
backtrack(res, [], nums, 0)
return res
def backtrack(res, temp, nums, start):
# print(temp)
res.append(temp)
for i in range(start, len(nums)):
backtrack(res, temp + [nums[i]], nums, i + 1)
答案 0 :(得分:6)
您将对同一列表对象的多个引用追加到result = subsets([1, 2, 3])
print([id(u) for u in result])
。我们可以通过
temp
这将打印出8个相同ID的列表。
因此,您对res
所做的各种更改会“丢失”,temp
的最终内容将是temp
的最终值的8个引用,并且这种情况是空列表。
解决此问题的简单方法是将res
的副本附加到def subsets(nums):
res = []
backtrack(res, [], nums, 0)
return res
def backtrack(res, temp, nums, start):
res.append(temp[:])
for i in range(start, len(nums)):
temp.append(nums[i])
backtrack(res, temp, nums, i + 1)
temp.pop() # Backtrack
print(subsets([1, 2, 3]))
。
[[], [1], [1, 2], [1, 2, 3], [1, 3], [2], [2, 3], [3]]
<强>输出强>
def subsets(seq):
z = [[]]
for x in seq:
z += [y + [x] for y in z]
return z
FWIW,我意识到这个练习的主要观点是练习递归,但在Python中最好避免递归,除非你真的需要它(例如,用于处理像树一样的递归数据结构)。但这是一个更紧凑的迭代解决方案。
print
要查看其工作原理,我们可以稍微扩展一下,然后添加def subsets(seq):
z = [[]]
for x in seq:
print('z =', z, 'x =', x)
w = []
for y in z:
w += [y + [x]]
z += w
return z
result = subsets([1, 2, 3])
print(result)
来电。
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]]
<强>输出强>
z
我们从包含单个空列表的列表w
开始。
在每个循环中,我们通过循环z
并使w
中的每个项目与z
中的相应项目的副本一起使用当前{x
来创建新列表z
附加{1}}。然后,我们使用w
的内容扩展def subsets(seq):
w = len(seq)
for i in range(1<<w):
yield [u for u, v in zip(seq, reversed('{:0{}b}'.format(i, w))) if v=='1']
print(*subsets([1, 2, 3]))
。
只是为了好玩,这里是一个迭代生成器,它从位串生成子集(按自然顺序)。这种方法实际上非常有效,如果你想要一个大序列的所有子集而不消耗大量的RAM,这是很好的。
[] [1] [2] [1, 2] [3] [1, 3] [2, 3] [1, 2, 3]
<强>输出强>
$ cmd="... -more_switches -mode FOO BAR -mode BAZ -mode BAG -mode CAT DAT HAT -mode RAR"
$ mapfile -t modes < <(grep -oP -- '-mode \K.+?(?= -mode|$)' <<<"$cmd")
$ printf "%s\n" "${modes[@]}"
FOO BAR
BAZ
BAG
CAT DAT HAT
RAR
答案 1 :(得分:1)
变量是对实际值的引用。但是,由于Python列表是可变的,当您通过一个引用更改值时,另一个引用也将反映更改。
brew cask install jce-unlimited-strength-policy
在将其附加到修复程序之前复制一份列表。
>>> a = [1, 3]
>>> b = a
>>> b
[1, 3]
>>> b.append(1)
>>> b
[1, 3, 1]
>>> a
[1, 3, 1]
如其他答案中所述,您也可以使用def subsets(nums):
res = []
backtrack(res, [], nums, 0)
return res
def backtrack(res, temp, nums, start):
res.append([])
for i in temp:
res[-1].append(i);
for i in range(start, len(nums)):
temp.append(nums[i])
backtrack(res, temp, nums, i + 1)
temp.pop() # Backtrack
。