Ruby 资源效率-找到一个可能的数字组合以达到给定的总和
我在Ruby中使用这些算法:Ruby 资源效率-找到一个可能的数字组合以达到给定的总和,ruby,dynamic-programming,Ruby,Dynamic Programming,我在Ruby中使用这些算法: def subset_sum(inp, s) arr = [] loop.with_index{|_, i| arr << inp.combination(i+1).to_a.find{ |c| (c.inject(0) {|sum,x| sum + x}) == s}; break if !a.none? || i == inp.count } arr end subset_sum([1,
def subset_sum(inp, s)
arr = []
loop.with_index{|_, i| arr << inp.combination(i+1).to_a.find{
|c| (c.inject(0) {|sum,x| sum + x}) == s}; break if !a.none? || i == inp.count }
arr
end
subset_sum([1,2,3,4,5,6], 15)
不幸的是,这两条路径都是资源密集型的。如果我增加传入数组,计算将花费很长时间。告诉我,有没有解决这个问题的最佳Ruby方法?def find\u one\u subset\u suminp,sum
候选项=inp.filter{| i | i我知道数组的所有元素都是非负的 尝试以下递归
def subset_sum((first, *rest), target)
return (first == target ? [first] : nil) if rest.empty?
rv = subset_sum(rest, target)
return rv unless rv.nil?
return nil if first > target
return [first] if first == target
rv = subset_sum(rest, target-first)
rv.nil? ? nil : [first, *rv]
end
在第一个示例中,很快就找到了解决方案,但这只是因为数组的最后三个元素和为11。相反,当arr的元素被洗牌时,要生成arr1,需要相当长的时间来执行
为了了解发生了什么,让我们包含一些puts语句
def subset_sum((first, *rest), target)
puts "first = #{first}, rest = #{rest}, target = #{target}"
if rest.empty?
puts " rest is empty, return #{first == target ? [first] : nil}"
return first == target ? [first] : nil
end
rv = subset_sum(rest, target)
puts " rv #{first} not used"
puts " return #{rv}" unless rv.nil?
return rv unless rv.nil?
return nil if first > target
return [first] if first == target
rv = subset_sum(rest, target-first)
rv.nil? ? nil : [first, *rv]
end
总的来说,我不相信这会比使用Arraycombination快很多,但是可以做一些基准测试
使用动态规划可以获得进一步的改进。状态变量是数组前n个元素中使用的变量之和。例如,如果前四个元素是
a4 = [1,2,3,4]
那么1到4个元素的所有组合将是:
all = (1..4).each_with_object([]) do |n,a|
a4.combination(n).each { |aa| a << aa.sum }
end
#=> [1, 2, 3, 4, 3, 4, 5, 5, 6, 7, 6, 7, 8, 9, 10]
如果已知数组的值都是非负的,如果目标值是,比如说,6,那么状态变量的可能值将限制为以下值
all.uniq.select { |a| a <= 5 }
#=> [1, 2, 3, 4, 5]
这将是有效的,a4的计算是根据a3的结果得出的,依此类推
如果需要,我可以演示如何编写动态编程解决方案。将选择替换为检测或查找。当找到一个时,它会停止搜索。此外,.inject:+可以写为.sum,但不要期望加速。已知给定数组的元素是否为非负?Cary,非常感谢您的决定。这很有效。。。你的问题的答案是“是”。我正在葡萄树上构建一个简单的ATM,所以数组的所有元素都是非负的。我的解决方案很简单,但我以前从未使用过葡萄。这是我的“尝试”:我不想把你的时间浪费在我的愚蠢上。但是,如果您有几分钟的空闲时间,我将非常感谢您对代码的任何评论和选项。谢谢你,卡里斯沃夫兰,请看一看。该方法返回nil:subset_sum[1,1,1,1,2,2,5,5,5,5,5,5,10],6=>nil谢谢,这非常有效!
a4 = [1,2,3,4]
all = (1..4).each_with_object([]) do |n,a|
a4.combination(n).each { |aa| a << aa.sum }
end
#=> [1, 2, 3, 4, 3, 4, 5, 5, 6, 7, 6, 7, 8, 9, 10]
all_uniq = all.uniq
#=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
all.uniq.select { |a| a <= 5 }
#=> [1, 2, 3, 4, 5]