我试图编写一个程序作为输入:
arr
)列表sum
)它应该返回arr
中所有可能的数字组合,总计为sum
。
这是我到目前为止所拥有的:
def printAllSubsetsRec(arr, v, sum):
if sum == 0:
return [v]
if len(arr) == 0:
return
v1 = [] + v
v1.append(arr[0])
without_first = printAllSubsetsRec(arr[1:], v, sum)
with_first = printAllSubsetsRec(arr[1:], v1, sum - arr[0])
if with_first and without_first:
return with_first + without_first
elif with_first:
return with_first
elif without_first:
return without_first
def array_sums(arr, sum):
v = []
return printAllSubsetsRec(arr, v, sum)
问题在于它不会返回包括重复在内的所有子集。
例如:
print(array_sums([1,3,5],5))
# [[1, 1, 1, 1, 1], [1, 1, 3], [1, 3, 1], [3, 1, 1], [5]]
我该怎么做?
答案 0 :(得分:1)
每次递归时,我为arr
中的每个数字创建了一个新分支。我保留了总和与目标匹配的分支,并停止探索总和超过目标的分支。
更快(沿着呼叫链向下传递分支的累积总和)
def array_sums(arr: Set[int], target: int) -> List[List[int]]:
smallest = min(arr)
def go(
in_progress: List[Tuple[List[int], int]],
complete: List[List[int]]
) -> List[List[int]]:
now_in_progress, newly_complete = [], []
for branch, sum_ in in_progress:
for i in arr:
# anything short of `target` by less than `smallest` will overshoot
if sum_ + i <= target - smallest:
now_in_progress.append((branch + [i], sum_ + i))
elif sum_ + i == target:
newly_complete.append(branch + [i])
newly_complete += complete
return newly_complete if not now_in_progress else go(
now_in_progress, newly_complete
)
return go([([], 0)], [])
简单且纯粹的功能(计算每次递归的分支总数)
def array_sums(arr: Set[int], target: int) -> List[List[int]]:
def go(acc: List[List[int]]) -> List[List[int]]:
in_progress = [
branch + [i]
for branch in acc
for i in arr
if sum(branch) < target
]
complete = [branch for branch in acc if sum(branch) == target]
return complete if not in_progress else go(in_progress + complete)
return go([[]])
答案 1 :(得分:1)
您可以将递归与生成器一起使用:
def subsets(arr, _sum, c = []):
if sum(c) == _sum:
yield c
else:
for i in arr:
if sum(c+[i]) <= _sum:
yield from subsets(arr, _sum, c+[i])
print(list(subsets([1,3,5], 5)))
输出:
[[1, 1, 1, 1, 1], [1, 1, 3], [1, 3, 1], [3, 1, 1], [5]]