Arrays 获取scala中数组值组合的总和

Arrays 获取scala中数组值组合的总和,arrays,scala,functional-programming,Arrays,Scala,Functional Programming,我知道有一些类似的问题,但似乎仍然没有一个明确的答案,所以我会问它 我有一个数组,我试图找到正确的值,这些值的总和将等于限制值,或者从任何给定的组合中得到最接近的值(不超过该值) 根据这个答案,我得出以下结论: def getLimitArr(arr: Array[Int], limit: Int): Unit = { scala.util.Sorting.quickSort(arr) // Array(2, 3, 4, 5, 11, 34) var 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)

   }
返回:

   println(arr2.mkString(", ") + " = " + sum) // 5, 4 = 9
这是好的,但前提是(构成总和的)值可以从低于极限的最高值得出;在这个示例5中,我们可以看到,它与这个数组一起工作。但是如果此数组的限制值为12(
getLimitArr(arr,12)
),则它将返回
11=11
,而不是使用
5+4+3

我已经使用子集完成了这项工作,但是当数组大于10时,我会得到内存堆错误,因为它在能够获得答案之前正在制定所有组合


那么,我们应该如何做到这一点,使用内存效率高、当前格式或利用Scala的函数式编程功能呢?

当我们希望在找到第一个正确答案后立即终止时,递归通常很有用

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
  }
}
def getLimit(nums:Array[Int],limit:Int):Array[Int]={
val子集=nums.filter(限制>=)

如果(subset.sum这似乎是背包问题的一个变体,有一个已知的解决方案:它看起来是,但这并不能回答如何使用多个数组值编写一个有效的解决方案,并且不会导致内存堆错误的问题。谢谢,但是使用任意多个数组值;如果没有使用一两个数组值找到解决方案,我们将得到java.lang.OutOfMemoryError:GC开销限制超过了错误。我正在寻找可以处理多达30个数组值的东西。\u这肯定更好,这是一个有价值的答案,但它不能处理30个数组值,我忍不住觉得有一个更精简的解决方案,可以这么说,尽管我认为它不能处理多达30个数组值这可能是最好的选择,因此标记为正确。当然,如果任何人有任何补充,那么这将对其他人有用。谢谢
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
  }
}