我知道有一些类似的问题,但似乎仍然没有明确的答案,所以我会问它..
我有一个array
的值,我正在尝试找到正确的值,这些值将总和为limit
值,或者它可以从任何给定组合中获得最接近的值(不超过它)。
使用这个答案https://stackoverflow.com/questions/23168934/calculating-minimal-subset-with-given-sum我有这个:
def getLimitArr(arr: Array[Int], limit: Int): Unit = {
scala.util.Sorting.quickSort(arr) // Array(2, 3, 4, 5, 11, 34)
var sum = 0L
var i = arr.length-1
val arr2 = ArrayBuffer[Integer]()
while (i >= 0 && sum < limit) {
if(sum + arr(i)<=limit) {
sum += arr(i)
arr2 += arr(i)
}
i -= 1 // 6, 5, 4, 3, 2, 1
}
println(arr2.mkString(", ") + " = " + sum)
}
在main方法中使用它调用它:
val arr = Array(3, 34, 4, 11, 5, 2)
getLimitArr(arr, 9)
返回:
println(arr2.mkString(", ") + " = " + sum) // 5, 4 = 9
这是好的,但只有当值(构成总和)可以从低于限制的最高值做出时;在这个例子中5 - 我们可以看到它与这个数组一起工作。但是,如果此数组的限制值为12(getLimitArr(arr, 12)
),那么它将返回11 = 11
而不是使用5 + 4 + 3
。
我是使用 子集 完成的,但当数组超过10时,我得到 内存堆错误 因为它正在制定所有组合才能获得答案。
那么我们如何通过提高内存效率,使用当前格式或利用Scala的函数编程功能来实现这一目标呢?
答案 0 :(得分:0)
当我们想要在找到第一个正确答案后立即终止时,递归通常很有用。
def getLimit(nums: Array[Int], limit: Int): Array[Int] = {
val subset = nums.filter(limit.>=)
if (subset.isEmpty) Array()
else (1 to subset.length).flatMap(subset.combinations)
.find(_.sum == limit)
.fold(getLimit(subset, limit-1))(identity)
}
getLimit(Array(3, 34, 4, 11, 5, 2), 5) // res0: Array[Int] = Array(5)
getLimit(Array(3, 34, 4, 11, 5, 2), 9) // res1: Array[Int] = Array(4, 5)
getLimit(Array(3, 34, 4, 11, 5, 2), 12) // res2: Array[Int] = Array(3, 4, 5)
getLimit(Array(3, 34, 4, 11, 5, 2), 24) // res3: Array[Int] = Array(3, 4, 11, 5)
请注意,最后一个总和为23,因为没有总和为24的组合。
<强>更新强>
添加了更好的快捷方式,现在该方法是尾递归的。
def getLimit(nums: Array[Int], limit: Int): Array[Int] = {
val subset = nums.filter(limit.>=)
if (subset.sum <= limit) subset
else {
val res = (1 to subset.length).view
.flatMap(subset.combinations)
.find(_.sum == limit)
if (res.isEmpty) getLimit(subset, limit-1)
else res.get
}
}