最近,我实现了这个二进制搜索,它应该在6秒内运行Scala,但它在检查分配的机器上运行12-13秒。
在阅读代码之前请注意:输入包含两行:第一行 - 要搜索的数字列表,第二行 - "搜索术语"在数字列表中搜索。预期输出只列出数字列表中每个术语的索引。每个输入最大长度为10 ^ 5,每个数字最大为10 ^ 9。
例如:
Input:
5 1 5 8 12 13 //note, that the first number 5 indicates the length of the
following sequence
5 8 1 23 1 11 //note, that the first number 5 indicates the length of the
following sequence
Output:
2 0 -1 0 -1 // index of each term in the input array
我的解决方案:
object BinarySearch extends App {
val n_items = readLine().split(" ").map(BigInt(_))
val n = n_items(0)
val items = n_items.drop(1)
val k :: terms = readLine().split(" ").map(BigInt(_)).toList
println(search(terms, items).mkString(" "))
def search(terms: List[BigInt], items:Array[BigInt]): Array[BigInt] = {
@tailrec
def go(terms: List[BigInt], results: Array[BigInt]): Array[BigInt] = terms match {
case List() => results
case head :: tail => go(tail, results :+ find(head))
}
def find(term: BigInt): BigInt = {
@tailrec
def go(left: BigInt, right: BigInt): BigInt = {
if (left > right) { -1 }
else {
val middle = left + (right - left) / 2
val middle_val = items(middle.toInt)
middle_val match {
case m if m == term => middle
case m if m <= term => go(middle + 1, right)
case m if m > term => go(left, middle - 1)
}
}
}
go(0, n - 1)
}
go(terms, Array())
}
}
是什么让这段代码变得如此之慢?谢谢
答案 0 :(得分:4)
我担心
的复杂性results :+ find(head)
将项目附加到长度为L的列表中为O(L)(请参阅here),因此如果要计算n个结果,则复杂度将为O(n * n)。
尝试使用可变ArrayBuffer而不是Array来累积结果,或者只是通过find函数映射输入术语。
换句话说,替换
go(terms, Array())
与
terms.map( x => find(x) ).toArray
顺便说一句,对问题的限制很小,使用BigInt是过度的,可能会使代码显着变慢。正常的整数应该足够大以解决这个问题。