3

I have written a program to print all the permutations of the string using backtracking method.

# include <stdio.h>
/* Function to swap values at two pointers */
void swap (char *x, char *y)
{
    char temp;
    temp = *x;
    *x = *y;
    *y = temp;
}

/* Function to print permutations of string
   This function takes three parameters:
   1. String
   2. Starting index of the string
   3. Ending index of the string. */

void permute(char *a, int i, int n) 
{
   int j; 
   if (i == n)
     printf("%s\n", a);
   else
   {
        for (j = i; j <= n; j++)
       {
              swap((a+i), (a+j));
              permute(a, i+1, n);
              swap((a+i), (a+j)); //backtrack
           }
   }
} 

/* Driver program to test above functions */
int main()
{
   char a[] = "ABC";  
   permute(a, 0, 2);
   getchar();
   return 0;
}

What would be time complexity here.Isn't it o(n2).How to check the time complexity in case of recursion? Correct me if I am wrong.

Thanks.

Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208
starkk92
  • 5,754
  • 9
  • 43
  • 59
  • 1
    There are `n!` permutations of `n` elements, so the complexity is at least `O(n!)`. – Daniel Fischer Jan 16 '13 at 07:03
  • `for (j = i+1; j < n; j++)` plus `permute(a, 0, 3);` in main() – wildplasser Jan 16 '13 at 11:14
  • I have given detailed explanation in C# here. Have a look at here. http://stackoverflow.com/a/26172890/2466650 Did not noticed that I can comment here, so added this link in the below answer earlier. – Sai Oct 03 '14 at 03:37

3 Answers3

3

The complexity is O(N*N!), You have N! permutations, and you get all of them.
In addition, each permutation requires you to print it, which is O(N) - so totaling in O(N*N!)

amit
  • 175,853
  • 27
  • 231
  • 333
  • @kaitian: There are `O(N!)` permutations indeed, but the code also prints every one of those. Each is of length `N`, thus you need to write a string of length `N` for every permutation, which results in total time complexity of `O(N * N!)` – amit Jan 16 '13 at 08:25
  • yes, you are right~~~ what I want to say is that, complexity of permutations are always O(N!) even if you cut some branches off. C++ STL has achieved a non-recursive version called next_permutatin. By the way, N is very small for N! Haha – kaitian521 Jan 16 '13 at 08:30
  • It seems this isn't the complexity of that program - please see my answer below. – Déjà vu Jan 17 '13 at 09:06
  • @ring0: The "answer below" ignore `printf` - no reason to do so, the program includes it. Each printf is `O(N)` - resulting in `O(N * N!)` run time. – amit Jan 17 '13 at 09:09
  • @amit answered below - I'm just trying to help the OP understanding what is the [big O notation](http://en.wikipedia.org/wiki/Big_O_notation). – Déjà vu Jan 17 '13 at 09:23
  • To be _really_ pedantic, it's only O(n*n!) if we assume that arithmetic and memory access take constant time, which is not really possible if we let n grow without bound. But then again, the code as given is using finite-length numeric types, and presumably running on a computer with finite memory, so n _cannot_ grow unboundedly large; to someone so pedantic that they'd insist on counting addition as an O(log n) operation, _any_ real-world program is O(1) anyway. So, for practical purposes, I agree that your O(n*n!) answer is correct: +1. – Ilmari Karonen Jan 19 '13 at 12:31
  • Add to this answer, I have given detailed explanation in C# here. Have a look at here. http://stackoverflow.com/a/26172890/2466650 – Sai Oct 03 '14 at 03:33
2

My answer is going to focus on methodology since that's what the explicit question is about. For the answer to this specific problem see others' answer such as amit's.

When you are trying to evaluate complexity on algorithms with recursion, you should start counting just as you would with an iterative one. However, when you encounter recursive calls, you don't know yet what the exact cost is. Just write the cost of the line as a function and still count the number of times it's going to run.

For example (Note that this code is dumb, it's just here for the example and does not do anything meaningful - feel free to edit and replace it with something better as long as it keeps the main point):

int f(int n){ //Note total cost as C(n)
  if(n==1) return 0; //Runs once, constant cost
  int i;
  int result = 0; //Runs once, constant cost
  for(i=0;i<n;i++){
    int j;
    result += i; //Runs n times, constant cost
    for(j=0;j<n;j++){
      result+=i*j; //Runs n^2 times, constant cost
    }
  }
  result+= f(n/2); //Runs once, cost C(n/2)
  return result;
}

Adding it up, you end up with a recursive formula like C(n) = n^2 + n + 1 + C(n/2) and C(1) = 1. The next step is to try and change it to bound it by a direct expression. From there depending on your formula you can apply many different mathematical tricks.

For our example:

For n>=2: C(n) <= 2n^2 + C(n/2)

since C is monotone, let's consider C'(p)= C(2^p): C'(p)<= 2*2^2p + C'(p-1)

which is a typical sum expression (not convenient to write here so let's skip to next step), that we can bound: C'(p)<=2p*2^2p + C'(0)

turning back to C(n)<=2*log(n)*n^2 + C(1)

Hence runtime in O(log n * n^2)

Khaur
  • 770
  • 3
  • 10
1

The exact number of permutations via this program is (for a string of length N)

  • start : N p. starting each N-1 p. etc...
  • number of permutations is N + N(N-1) + N(N-1)(N-2) + ... + N(N-1)...(2) (ends with 2 since the next call just returns)
  • or N(1+(N-1)(1+(N-2)(1+(N-3)(1+...3(1+2)...))))

Which is roughly 2N!

Adding a counter in the for loop (removing the printf) matches the formula

  • N=3 : 9
  • N=4 : 40
  • N=5 : 205
  • N=6 : 1236 ...

The time complexity is O(N!)

Déjà vu
  • 28,223
  • 6
  • 72
  • 100
  • No reason to ignore the `printf`, it is part of the program and each invokation of it is `O(N)`. – amit Jan 17 '13 at 09:09
  • *printf* is an extension of the processing for each permutation. It is a linear process that doesn't grow by itself anywhere near N! when N grows. See the [big O notation](http://en.wikipedia.org/wiki/Big_O_notation). – Déjà vu Jan 17 '13 at 09:21
  • So? Note it is not O(N! + N), it is O(N! * N), Note that N!*N is asymptotically larger then N!, (`lim (N->infinity) N!*N/N! = lim (N->infinity) N = infinity`). **By definition of big O**, it means N!*N is NOT in `O(N!)`. I do agree there are N! permutations of course, I disagree you can "ignore" the `printf` function from the analysis. – amit Jan 17 '13 at 09:24
  • So if an algorithm goes according to the function `f(n) = n*n` it's `O(n²)` but if each of its iteration does *printf* it's `O(n³)`? I don't think so. – Déjà vu Jan 17 '13 at 09:28
  • It depends what it prints, if it prints something that its length is `O(n)` - then yes. How printf works? It iterates over all characters in the array/string and print each of them to screen, so inside your algorithm you have a function that iterates `n` more times. If this loop in the function is called `n^2` times, you actually have `n^3` operations. – amit Jan 17 '13 at 09:31
  • Or in other words, will `for (int i =0 ; i < n; i++) for (int j = 0; j < n; j++) for (int k = 0; k < n; k++) putchar(arr[k]);` be O(n^2) or O(n^3)? Of course `O(n^3)`. But the printf is just encapsulating the last loop in a function. (Not exactly of course, it is more efficient then this, but it still essentially reads every character in the array) – amit Jan 17 '13 at 09:33
  • Hmm the OP prog displays the string each time, (constant) time, this doesn't affect the time *complexity* of the algorithm. If you come around, I'd be glad to have a coffee with you and discuss about that - thanks for the discussion anyway. – Déjà vu Jan 17 '13 at 09:37
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/22891/discussion-between-amit-and-ring0) – amit Jan 17 '13 at 09:39
  • Ok, the answer seems to be `O(nn!)` (not in my algo since I specifically removed the `printf`). But in the original algo, I was assuming a constant time for `printf`, which in fact depends upon *n*. Thus there is an added *n* factor to the complexity. Interesting discussion. – Déjà vu Jan 19 '13 at 13:13