我需要从[{1}}获取所有可能的数字组合,其等于denom_arr
。
amt
这种情况会产生:
denom_arr = [4,3,1]
amt = 10
[4, 4, 1, 1]
[3, 3, 3, 1]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
[4, 3, 1, 1, 1]
问题是我写的代码在[4, 3, 3]
后破解了,我不知道如何让它循环到同一个索引以获取案例1-3
4-6+
更新
我知道这可以通过使用memoization / dynamic编程技术进行递归来完成,但我试图在循环中严格执行此操作以便测试理论。
答案 0 :(得分:5)
我会递归地执行此操作
def possible_sums(arr, amt)
return [[]] if amt == 0
return [] if amt < 0
arr.reduce([]) do |sums, e|
sums.concat(
possible_sums(arr, amt-e)
.map { |sum| sum.unshift(e).sort }
)
end.uniq
end
p possible_sums([4,3,1], 10)
# => [
# [1, 1, 4, 4], [3, 3, 4], [1, 1, 1, 3, 4], [1, 1, 1, 1, 1, 1, 4],
# [1, 3, 3, 3], [1, 1, 1, 1, 3, 3], [1, 1, 1, 1, 1, 1, 1, 3],
# [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
# ]
虽然这可能是低效的,因为它重复工作,但这可以通过使用动态编程(基本上,记忆递归函数的结果)来缓解。
UPDATE 以下是一个迭代解决方案:
def possible_sums_it(arr, amt)
sums = Array.new(amt+1) { [] }
sums[0] << []
(1..amt).each do |i|
arr.each do |e|
if i-e >= 0
sums[i].concat(
sums[i-e].map { |s| [e, *s].sort }
)
end
end
sums[i].uniq!
end
sums[amt]
end
这实际上是问题的动态编程算法。
因此,如果你恰到好处地眯着眼睛,你会看到它正在做的事情,就是计算0
到amt
数组sums
之前的所有可能总和使用什么基本上是递归算法,但我们在sums
中查找我们事先计算过的值,而不是递归调用。
这是有效的,因为我们知道sums[i]
sums[j]
之前我们不需要j < i
。