Given the following function:
Function f(n,m)
if n == 0 or m == 0: return 1
return f(n-1, m) + f(n, m-1)
What's the runtime compexity of f
? I understand how to do it quick and dirty, but how to properly characterize it? Is it O(2^(m*n))
?
The runtime of
f(n, m)
is inO(f(n, m))
. This is easily verified by the following observation:The function
f
is called equally often asg
. Furthermore, the functiong
is called exactlyg(n, m)
times to evaluate the result ofg(n, m)
. Likewise, the functionf
is called exactlyg(n, m) = 2*f(n, m)-1
times in order to evaluate the result off(n, m)
.As @Yves Daoust points out in his answer,
f(n, m) = (n + m)!/(n!*m!)
, therefore you get a non-recursive runtime ofO((n+m)!/(n!*m!))
forf
.Understanding the Recursive Function
The values look like a Pascal triangle to me:
Solving the Recursion Equation
The values of Pascal's triangle can be expressed as binomial coefficients. Translating the coordinates one gets the solution for f:
which is a nice term symmetric in both arguments n and m. (Final term first given by @Yves Daoust in this discussion)
Pascal's Rule
The recursion equation of f can be derived by using the symmetry of the binomial coefficients and Pascal's Rule
Determing the Number of Calls
The "number of calls of f" calculation function F is similar to f, we just have to add the call to f itself and the two recursive calls:
(Given first by @blubb in this discussion).
Understanding the Number of Calls Function
If we write it down, we get another triangle scheme:
Comparing the triangles value by value, one guesses
(Result first suggested by @blubb in this discussion)
Proof
We get
as it should and examining the otherwise clause, we see that
Thus if we use (*) and the otherwise clause for f, the otherwise clause for F results.
As the finite difference equation and the start condition for F hold, we know it is F (uniqueness of the solution).
Estimating the Asymptotic Behaviour of the Number of Calls
Now on calculating / estimating the values of F (i.e. the runtime of your algorithm).
As
we see that
So the runtime of this algorithm is
(Result first given by @Yves Daoust in this discussion)
Approximating the Runtime
Using the Stirling approximation
one can get a form without hard to calculate factorials. One gets
thus arriving at
(Use of Stirling's formula first suggested by @Yves Daoust in this discussion)
This is an instance of Pascal's triangle: every element is the sum of the two elements just above it, the sides being all ones.
So
f(n, m) = (n + m)! / (n! . m!)
.Now to know the number of calls to
f
required to computef(n, m)
, you can construct a modified Pascal's triangle: instead of the sum of the elements above, consider1 + sum
(the call itself plus the two recursive calls).Draw the modified triangle and you will quickly convince yourself that this is exactly
2.f(n, m) - 1
.You can obtain the asymptotic behavior of the binomial coefficients from Stirling's approximation. http://en.wikipedia.org/wiki/Binomial_coefficient#Bounds_and_asymptotic_formulas