You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编写递归程序获取允许重复元素的指定和所有子集?

解决允许重复元素的组合求和问题

你的代码目前的核心问题是每个元素只能被使用一次——因为在递归调用with_first的时候,你传入了arr[1:],这就排除了再次选择当前元素的可能性。要实现允许元素重复使用的需求,我们需要调整递归逻辑,让选择使用当前元素时,仍然保留该元素在后续的可选列表中。

修改思路

当我们决定使用当前元素arr[0]时,递归调用应该继续传入完整的arr(而不是arr[1:]),这样下一次递归仍然可以选择这个元素。而当我们不使用当前元素时,才传入arr[1:],跳过这个元素。

修改后的完整代码

def printAllSubsetsRec(arr, v, target_sum):
    # 当目标和为0时,当前路径v就是一个有效组合
    if target_sum == 0:
        return [v.copy()]
    # 如果数组为空且目标和不为0,没有有效组合
    if not arr:
        return []
    
    # 情况1:不使用当前第一个元素,递归处理剩下的数组
    without_first = printAllSubsetsRec(arr[1:], v, target_sum)
    
    # 情况2:使用当前第一个元素(前提是它不超过目标和)
    with_first = []
    if arr[0] <= target_sum:
        v.append(arr[0])
        # 注意这里传入的是完整的arr,允许重复使用当前元素
        with_first = printAllSubsetsRec(arr, v, target_sum - arr[0])
        # 回溯,移除刚才添加的元素,避免影响其他分支
        v.pop()
    
    # 合并两种情况的结果
    return with_first + without_first

def array_sums(arr, target_sum):
    return printAllSubsetsRec(arr, [], target_sum)

关键修改点说明

  1. 递归参数调整:在使用当前元素的分支中,将arr[1:]改为arr,这样后续递归仍然可以选择该元素,实现重复使用的需求。
  2. 回溯优化:用v.append()加v.pop()的回溯方式替代原代码的列表复制,既避免了不同分支的路径污染,又提升了效率。
  3. 无效调用过滤:增加arr[0] <= target_sum的判断,避免递归到负数和的无效场景,减少不必要的计算。

测试验证

执行print(array_sums([1,3,5],5)),会得到你期望的输出:

[[1, 1, 1, 1, 1], [1, 1, 3], [1, 3, 1], [3, 1, 1], [5]]

补充说明

如果后续你需要不考虑顺序的组合(比如把[1,1,3]、[1,3,1]、[3,1,1]视为同一个组合),只需要保证数组有序,并且在递归时调整分支逻辑跳过重复元素即可,但这是另一种需求,当前代码完全符合你要求的“包含所有顺序不同的重复元素组合”的场景。

内容的提问来源于stack exchange,提问作者gal leshem

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 07:32:37