递归函数的优化

时间:2019-03-20 16:21:52

标签: scala performance functional-programming

我正在尝试解决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中是否有排序列表?

1 个答案:

答案 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) }即可。