I am using this code https://stackoverflow.com/a/4240323/2655623 to create permutation and do some calculation on each result.
public static void permutation(String str) {
permutation("", str);
}
private static void permutation(String prefix, String str) {
int n = str.length();
int p = prefix.length();
if(p==5){
//do some calculation for |prefix| = 5
return;
}
for (int i = 0; i < n; i++){
permutation(prefix + str.charAt(i), str.substring(0, i) + str.substring(i+1, n));
}
}
this algorithm works great for me. However, I would like to see how I can remove duplicate characters so I don't calculate the prefix with again. for example for
permutation("aacccbbdeeeef");
I will process abcde about
A = 2 * 4*3*2*1 when a----
B = 2 * 4*3*2*1 when b----
C = 3 * 4*3*2*1 when c----
and so on...
// I hope you get the idea
I wonder if i can reduce the amount of duplicate calculation.
One way I thought was to sort the character orders, and only calculate one of each duplicate characters when I use FOR for them.
for (int i = 0; i < n; i++){
if(i>0 && str.charAt(i) == str.charAt(i-1)) continue;
permutation.....
}
this worked fine for me as just need the permutation once. It drastically reduce the number of calls when the number of repeated letters are high.
Now, to sum up, I would like to know if
Thank you very much.
is this guarantee than I will not miss any permutation?
Yes. If all the repeated characters are in blocks, like "aaabbccccc"
, the line of code
if(i>0 && str.charAt(i) == str.charAt(i-1)) continue;
is exactly what you need. It will not miss any permutation because it only skips over ones that would have been the same anyway. And it won't repeat any permutation because the equal characters are in blocks.
how can I prevent cases like a(1)ba(2)cd and a(2)ba(1)cd from happening when p=5. As for p=8 or 10, the trick I used will not be that efficient. so what I need to do?
I don't see the need to worry about input strings like "abacd"
at all. The set of permutations for this string is exactly the same as the set for "aabcd"
so it makes sense to sort the string right at the beginning (this will collect repeated characters into blocks), and call permutation("", sortedString);
. Doing it this way you can just use the trick you mentioned.
For long strings, it's going to be slow anyway just because there are lots of permutations and also because the method creates lots of string objects. These factors are much more significant that the minor inefficiency created by iterating over a slightly larger range than strictly necessary and using continue
.