如何编写递归程序获取允许重复元素的指定和所有子集?
解决允许重复元素的组合求和问题
你的代码目前的核心问题是每个元素只能被使用一次——因为在递归调用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)
关键修改点说明
- 递归参数调整:在使用当前元素的分支中,将
arr[1:]改为arr,这样后续递归仍然可以选择该元素,实现重复使用的需求。 - 回溯优化:用
v.append()加v.pop()的回溯方式替代原代码的列表复制,既避免了不同分支的路径污染,又提升了效率。 - 无效调用过滤:增加
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
相关产品推荐
相关产品推荐

