Reputation: 659
Consider the following code to permute a string containing unique characters from McDowell:
This code is based on a recursion and adds to each result by placing a character to every single spot. If the string contains n characters, then there are n+1 such places.
Since for every string (there are n! possible strings of length n), you add n+1 characters, the complexity should be 1! + 2! + ... + (n+1)!
The author says that the complexity is O(n!). Is this the same as O(1!+...+(n+1)!)? If so, why?
public static ArrayList<String> getPerms(String str){
if (str == null){
return null;
}
ArrayList<String> permutations = new ArrayList<String>();
if (str.length() == 0){
permutations.add("");
return permutations;
}
char first = str.charAt(0);
String remainder = str.substring(1);
ArrayList<String> words = getPerms(remainder);
for (String word: words){
for (int j = 0; j <= word.length(); j++){
String s = insertCharAt(word, first, j);
permutations.add(s);
}
}
return permutations;
}
public static String insertCharAt(String s, char c, int j){
String start = s.substring(0, j);
String end = s.substring(j+1);
return start + c + end;
}
Upvotes: 0
Views: 657
Reputation: 385710
Let's define F(n)
as the length of the list returned by getPerms
when you pass it a string of length n
.
By inspection of the base case, we see that F(0) == 1
.
In the recursive case, with a string of length n > 0
, getPerms
calls itself recursively on a string of length n-1
. It gets back a list of length F(n-1)
(that is the definition of F
) and stores the list in words
. For each element of words
, it adds n
elements to permutations
. Thus permutations
will have n * F(n-1)
elements when it is returned.
Therefore, F(n) == n * (n-1) * (n-2) * ... * 1 == n!
. The getPerms
function returns a list of length n!
given a string of length n
.
Now, what is the complexity of getPerms
? I'll assume we're talking about time complexity. Well, it performs ∑i=0ni! list appends in total (n! for the outermost call, plus (n-1)! for the first recursive call, plus (n-2)! for the second recursive call, etc.). So you could say the complexity is O(∑ni!) list appends.
But list appends aren't the only computation here. We copy a lot of characters around when we join strings in Java.
Let's say G(n)
is the number of character copies performed by a call to getPerms
when you pass a string of length n
.
By inspection of the base case, we see that G(0) == 0
.
In the recursive case, getPerms
calls itself on a string of length n-1
, which performs G(n-1)
character copies and returns a list of F(n-1)
strings, each of length n-1
. Then getPerms
copies each of those strings n
times, inserting another character into each copy, so F(n-1) * n * n == n * n!
characters copied directly in the getPerms
call, in addition to the G(n-1)
from the recursion.
Thus the number of characters copied by a call to getPerms
is O(∑i=0ni * i!).
Upvotes: 1