Convert normal recursion to tail recursion

后端 未结 6 775
悲哀的现实
悲哀的现实 2020-12-13 07:30

I was wondering if there is some general method to convert a \"normal\" recursion with foo(...) + foo(...) as the last call to a tail-recursion.

For exa

6条回答
  •  忘掉有多难
    2020-12-13 07:52

    It is indeed possible. The way I'd do this is to begin with List(1) and keep recursing till you get to the row you want. Worth noticing that you can optimize it: if c==0 or c==r the value is one, and to calculate let's say column 3 of the 100th row you still only need to calculate the first three elements of the previous rows. A working tail recursive solution would be this:

    def pascal(c: Int, r: Int): Int = {
      @tailrec
      def pascalAcc(c: Int, r: Int, acc: List[Int]): List[Int] = {
        if (r == 0) acc
        else pascalAcc(c, r - 1,
        // from let's say 1 3 3 1 builds 0 1 3 3 1 0 , takes only the
        // subset that matters (if asking for col c, no cols after c are
        // used) and uses sliding to build (0 1) (1 3) (3 3) etc.
          (0 +: acc :+ 0).take(c + 2)
             .sliding(2, 1).map { x => x.reduce(_ + _) }.toList)
      }
      if (c == 0 || c == r) 1
      else pascalAcc(c, r, List(1))(c)
    }
    

    The annotation @tailrec actually makes the compiler check the function is actually tail recursive. It could be probably be further optimized since given that the rows are symmetric, if c > r/2, pascal(c,r) == pascal ( r-c,r).. but left to the reader ;)

提交回复
热议问题