繁体   English   中英

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

[英]Recursive program to get all subsets with given sum includes repetitions

我正在尝试编写一个作为输入的程序:

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

我怎样才能做到这一点?

在每次递归时,我为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([[]])

您可以使用生成器的递归:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM