Search code examples
javarecursiontime-complexitypascals-triangle

Multiple time complexity solutions for recursive Pascal triangle algorithm?


I have created the following simple algorithm in Java that computes the Pascal triangle in a recursive way, in the form of a 2D list of ints:

public class PascalTriangleRec{
    private final int[][] points;

    public PascalTriangleRec(int size){
        points = new int[size][];
        for (int i =0;i<size;i++){
            int[] row  = new int[i+1];
            for (int j = 0;j<=i;j++){
                row[j]=getValueAtPoint(i,j);
            }
            points[i]=row;
        } 
    }
    public static int getValueAtPoint(int row, int col){
        if (col == 0 || col == row) return 1;
        else return getValueAtPoint(row-1,col-1) + getValueAtPoint(row-1,col);
    }
}

I need to know the time complexity of this algorithm. I found another question on StackOverflow that gives the time complexity of the getValueAtPoint function as O(2^n/sqrt(n)). I figured that since this function is embedded in two nested for loops, the time complexity of the entire Pascal triangle is O(sqrt(n^3)*2^n). I am pretty sure this reasoning is correct.

On the other hand I devised a completely different way to think about this problem, which goes as follows:

There is a certain property of Pascal triangles called Pascal's Corollary 8. This property states that the sum of all the coëfficients on a given row r is equal to 2^r, with r starting at 0.

One can also note that the getValueAtPoint function from my code sample will keep recursively calling itself until it returns 1 at some point. This means that all the coëfficients in the Pascal triangle are formed by adding 1 as many times as the value of that coëfficient.

Since adding 1s takes a constant time, one can say that the time needed to compute a given row in the triangle is equal to some constant time multiplied by the combined value of all the coëfficients in that row. This means that the time complexity of a given row r in the triangle must be 2^r.

The time needed to compute the entire triangle is equal to the sum of the time needed to calculate all the rows in the triangle. This results in a geometric series, which computes the sum of all 2^r for r going from 0 to n-1.

Using the summation property of the geometric series, this series can be rewritten in the following form.

This means that the time complexity of the algorithm according to this last derivation is O(2^n).

These two approaches yield different results, even though they both seem logical and correct to me. My question is in the first place if both these approaches are correct, and if both can be seen as correct at the same time? As I view it both of them are correct, but the second one is more accurate since for the first one the worst-case scenario is taken for the getValueAtPoint function, and applied to all coëfficients, which is clearly not the case in reality. Does this mean that the first one becomes incorrect, even though the logic behind it is correct, just because a better approach exists?


Solution

  • The simple answer is "too many variables". First of all, your analysis is exactly correct: the complexity depends on the sum of all the values computed. The same logic underlies the answer that got you O(2^n/sqrt(n)).

    There are two problems:

    • Little problem: Stirling's approximation is just that: some terms are elided. I think they fall out when you combine all the loops, but I'd have to work through the nasty details to be sure.
    • Big problem: the values of n you combine are not the same n. That last n value you incorporated is i running from 0 to size; each value of i becomes n for an initial call to getValueAtPoint.

    Try doing the sum from 0 to n on your previous complexity, and see what you get?

    .