如何从数组中找到精确的(最小)元素以匹配给定的总和
Posted
技术标签:
【中文标题】如何从数组中找到精确的(最小)元素以匹配给定的总和【英文标题】:How to find exact (minimum) elements from array to match given sum 【发布时间】:2019-09-12 07:53:38 【问题描述】:我想要一个返回最小元素数组以匹配给定总和的方法
def find_elements arr, sum
#logic here
end
例子
arr = [10, 10, 20, 20, 30, 40, 50, 60]
find_elements arr, 50 #should return [50]
find_elements arr, 100 #should return [60, 40]
注意:- 如果没有与总和匹配的组合,则找到接近总和且小于总和的最小元素
find_elements arr, 75 #should return [60, 10]
【问题讨论】:
这看起来很像knapsack problem。 @Marek,我不这么认为,因为 OP 想要找到“匹配给定总和的最小元素子数组”(假设存在这样的子数组),与背包问题不同,是 NP 完全的。 @Salil - [60, 10] 或 [60, 40] 如何是子数组? 无论你想要一个方法,不要犹豫写它。 @CarySwoveland notexact: '注意:- 如果没有与总和匹配的组合,则找到接近总和且小于总和的最小元素' 【参考方案1】:只是出于好奇。可能不是性能最好的。
knapsack = ->(arr, sum) do
arr = arr.reject(&sum.method(:<)).sort.reverse
(1..arr.size).reduce([]) do |acc, i|
result =
arr.combination(i).reduce([]) do |acc, comb|
curr = comb.sum
break comb if curr == sum
(curr > acc.sum and curr < sum) ? comb : acc
end
curr = result.sum
break result if curr == sum
(curr > acc.sum and curr < sum) ? result : acc
end
end
烟雾测试。
knapsack.([10, 10, 20, 20, 30, 40, 50, 60], 50)
#⇒ [50]
knapsack.([10, 10, 20, 20, 30, 40, 50, 60], 110)
#⇒ [60, 50]
knapsack.([10, 10, 20, 20, 30, 40, 50, 60], 90)
#⇒ [60, 30]
knapsack.([10, 10, 20, 20, 30, 40, 50, 60], 75)
#⇒ [60, 10]
knapsack.([10, 10, 20, 20, 30, 40, 50, 60], 500)
#⇒ [60, 50, 40, 30, 20, 20, 10, 10]
【讨论】:
谢谢,有什么办法吗?更高效?【参考方案2】:我尝试了类似以下的方法,效果很好(但不确定我是否遗漏了任何边缘情况)
class Array
def head_tail
head, *tail = *self
[head, tail]
end
end
def find_elements array, sum
head, tail = array.head_tail
return unless head
if head < sum
[ head, *find_elements(tail, (sum - head))]
elsif head == sum
head
elsif head > sum
find_elements(tail, sum)
end
end
数组元素按降序排列,如array = [60, 50, 40, 30, 20, 20, 10, 10]
【讨论】:
以上是关于如何从数组中找到精确的(最小)元素以匹配给定的总和的主要内容,如果未能解决你的问题,请参考以下文章