javadata-structurestime-complexity

Explain time complexity of permutations using the mathematical expression


This is my code for computing all the permutations for the input array.

public class Permutations {
    public static void main(String[] args) {
        int[] a = {3, 1, 4};
        permutations(a, new int[a.length], new ArrayList<>());
    }
    
    private static void permutations(int[] a, int[] map, List<Integer> ds) {
        if(ds.size() == a.length) {
            System.out.println(ds);
            return;
        }
        
        for(int i = 0; i < a.length; i++) {
            if(map[i] != -1) {
                ds.add(a[i]);
                map[i] = -1;
                permutations(a, map, ds);
                ds.remove(ds.size()-1);
                map[i] = 0;
            }
        }
    }
}

I wanted to know the time complexity for this program, so, I decided to solve it using mathematical expression:

T(n) = n*T(n-1)
     = n*[(n-1)*T(n-2)]
     = n*(n-1)*(n-2)*--*T(0)
     = n!

So, I got n! using my mathematical expression, but I see more number of recursive calls going on in recursive tree.

For n = 3, n!= 6 where as recursive tree has 15 recursive calls.

enter image description here

Help me how in solving the time complexity correctly using mathematical expression.


Solution

  • Your mathematical analysis only counts the leaves of the recursion tree.

    To count each recursive call, you need to add 1 to account for the current call. So for the deepest call we have 𝑇(0) = 1, and for the top-level call we have:

    For 𝑛=3 this is 1 + 3 + 6 + 6 = 16, which matches what you found in your drawing.

    Note however that the count of recursive calls is in this case not the whole story for determining the time complexity: Each time the for loop executes, it iterates the complete a array, so that represents O(𝑛) work no matter how many times the if condition is false.

    This means that in terms like (𝑛−1)𝑇(𝑛−2) we only count the work done in the if block (which executes 𝑛−1), but don't account for the loop overhead that makes 𝑛 iterations, so this term should not be 1+(𝑛−1)𝑇(𝑛−2), but 𝑛+(𝑛−1)𝑇(𝑛−2).

    In short all terms should have their "1+" replaced with "𝑛+":

    The most significant term is 𝑛𝑛!