递归程序获取具有给定总和的所有子集,包括重复

时间:2019-05-19 09:59:29

标签: python recursion

我试图编写一个程序作为输入:

  1. 允许的号码(arr)列表
  2. 总计(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]]

我该怎么做?

2 个答案:

答案 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]]