Calculating Minimal Subset With Given Sum

醉酒当歌 提交于 2020-01-17 01:12:45

问题


I was doing a problem in Scala and this is the summary of the task statement:

There is a list of integers (of length N, 0 < N < 10^5) and another integer S (0 < S < 10^15). You are required to find the minimal size of the minimal subset of the given list of which the sum of elements (in the subset) is greater than or equal to S.

Input is given as below:
4
4 12 8 10
4
4 13 30 100

Output for above example:
1
2
3
-1

First line is length of array, the second is the array of integers (0 < A[i] < 10^9), the third is the number of test cases (0 < T < 10^5) and the fourth contains the S (for each test case).

Here's what I tried: The elements selected do not matter. So I sorted the list of given integers largest first. Then I selected the first one checked if its greater than S. If not, I selected the second element also, and so on until the sum becomes greater than or equal to S.

This algorithm works and I got many test cases correct. But I'm getting Time Limit Exceeded for some. If you can point out how I could make this faster or if there's a better way to do this, it would be much appreciated.

My code (Scala):

object Solution {
  def main(args: Array[String]) {
    val n = readInt()
    val arr: Array[Long] = readLine().split(" ").map(_.toLong).sortWith(_ > _)

    val sums: Array[BigInt] = new Array(n)
    sums(0) = arr(0)
    for(i <- 1 until n) sums(i) = sums(i-1) + arr(i)

    val t = readInt()
    for(i <- 1 to t) {
      val s:BigInt = BigInt(readLong())
      if(sums(n-1) < s)
        println(-1)

      else {
        var i = 0
        while(sums(i) < s) i += 1
        println(i + 1)
      }
    }
  }
}

回答1:


Making a full list of sums is unnecessary, and using BigInt is wasteful regardless--a Long can hold up to 9.2e18, and you are promised that only 1e15 is going to appear. (In fact, I think 1e15 was chosen so that even a Double can hold the answer without loss of precision.)

Also, you can use a fast sort on primitives rather than a slow generic sort like _ > _ which ends up boxing the integers. So:

val arr = {
  val in = readLine().split(' ').map(_.toInt)
  java.util.Arrays.sort(in)
  in
}

Then, use an accumulator (Long will do):

var sum = 0L

and search for the answer with a while loop, keeping in mind that the biggest elements are last so you want to start at the end:

var i = arr.length-1
while (i >= 0 && sum < t) {
  sum += arr(i)
  i -= 1
}

Now you just need to check if you succeeded or failed before running out of elements:

val answer = {
  if (i < 0) -1
  else arr.length - i - 1
}



回答2:


Here it is(with O(N) memory used and O(N log N) time used)

scala> import math.{Ordering => Ord}
import math.{Ordering=>Ord}

scala> def search(src: Seq[Long], dst: Seq[Long]): Seq[Int] = {
     |   val cum = src.sorted(Ord.Long.reverse).scanLeft(0L)(_ + _)
     |   dst.map{ v => cum.indexWhere(x => x >= v) }
     | }
search: (src: Seq[Long], dst: Seq[Long])Seq[Int]

scala> search(Seq(4, 12, 8, 10), Seq(4, 13, 30, 100))
res6: Seq[Int] = List(1, 2, 3, -1)


来源:https://stackoverflow.com/questions/23168934/calculating-minimal-subset-with-given-sum

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!