我正在尝试解决hackerrank上的函数编程的Messy Medians问题。
我的解决方案(如下)太慢。它几乎使测试用例超时。
@tailrec
def calculate(steps: List[Int], states: List[List[Int]]): List[Int] = {
steps match {
case x::xs =>
if(x > 0) {
states match { //apend state
case Nil => calculate(xs, List(x) :: states)
case y :: _ => calculate(xs, (x :: y) :: states)
}
} else {
calculate(xs, states.drop(-x-1).head :: states) //rollback state
}
case Nil => states
.reverse
.map { // calculate median
case List(x) => x
case xs => xs.sorted.apply(if (xs.length % 2 != 0) xs.length/2 else xs.length/2 - 1)
}
}
}
如何优化它?最多可能有100000个输入状态。
当我使用TreeSet
而不是List
进行状态显示时,它开始工作得更快,但是在有重复数字的情况下,它就停止工作了。
Scala中是否有排序列表?
答案 0 :(得分:5)
我没有阅读算法(或问题),因此,我无法说出您的解决方案的正确性,但是以下是我在代码中发现的一些问题:
xs.sorted.length
的结果与xs.length
相同,这种浪费只是浪费。
List.apply
是线性时间。如果要按索引随机访问,请使用IndexedSeq
代替List
List.length
也是线性的。如果您要切换到IndexedSeq
,这是无关紧要的,但是您应该在将来牢记这一点。至少一次,一次只能做一次xs.length
,然后将结果保存到变量中。但是即使那样,它仍然是线性的。最好只是传递长度,而不是每次都计算长度。
您可能还需要考虑使用quickselect algorithm来计算O(logN)时间的中位数。
if(n % 2 != 0) n/2 else n/2 - 1
与(n-1)/2
是同一件事...并不是说它会影响您的性能(一旦您修复了.length
东西),但是看起来很奇怪。您也不需要List(x)
的特殊情况。只需{ xs => xs((xs.length-1)/2) }
即可。