0

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

  1. is this guarantee than I will not miss any permutation?
  2. 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?

Thank you very much.

Community
  • 1
  • 1
Soley
  • 1,716
  • 1
  • 19
  • 33

4 Answers4

1
  1. 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.

  1. 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.

Paul Boddington
  • 37,127
  • 10
  • 65
  • 116
  • 1
    Thank you for your help. I think I have to find a way to reduce the number of string that will be generated. I wonder if i can use the swap method to just alter one character at a time and keep all the changes in a char[] variable. I did it somehow on my calculation and it drastically reduced the computation time from 800ms to 16ms which it was so huge improvement for me. – Soley Apr 07 '16 at 06:02
0

Simple solution can be to store the characters into a Set (remove duplicates) and read them ;)

Amit Mahajan
  • 895
  • 6
  • 34
  • I was thinking about it, but the time and space required for this is huge, and I cannot afford it on a busy server. – Soley Apr 07 '16 at 05:59
0
public static void permutation(String str) { 
    Set<Character> charsSet = new HashSet<Character>();
    for (int i = 0; i < s.length(); i++){
        Character  c = new Character (s.charAt(i));
        charsSet.add(c);   
    }
    StringBuilder sb = new StringBuilder();
    for (Character  c : charsSet) {
        sb.append(c.charValue());
    }
    permutation("", sb.toString()); 
}

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));
    }
}
Matteo Baldi
  • 5,613
  • 10
  • 39
  • 51
  • this will remove duplicate characters which it shorten the permutation as well. for str=aaabbbbbb, it will generate the seq for 'ab' which it is another string from input string.This is an algorithmic error. – Soley Apr 07 '16 at 05:56
0

this is my variant for the "total signed permutations of length n"

Sample Dataset

2

Sample Output

-1 -2

-1 2

1 -2

1 2

-2 -1

-2 1

2 -1

2 1

total: 8

Follow this sample please:

private static int count = 0;

@Test
public void unsignedPermTest(){
    final int unsigendN = 2;
    final int n = unsigendN * 2;

    final int[] arr = new int[n];

    for(int i=1; i<=unsigendN;i++){
        arr[i-1] = i;
        arr[arr.length-i] = -i;
    }

    count = 0;
    permutation(arr, n, unsigendN);
    System.out.println("total: " + count);
}

public static void permutation(final int[] arr, final int n, final int k) {
    permutation(arr, "", n, k);
}

private static void permutation(final int[] arr, final String prefix, final int n, final int k) {

    if (k == 0)
    {
        final String res = prefix.substring(1);

        final String[] chars = res.split(" ");

        for(int i=0; i<chars.length;i++){
            for(int j=i+1; j<chars.length;j++){
                if(chars[i].replace("-", "").equals(chars[j].replace("-", ""))) return;
            }
        }

        count=count+1;
        System.out.println(res);
        return;
    }

    for (int i = 0; i < n; ++i) {
        permutation(arr, prefix + " " + arr[i], n, k - 1);
    }
}
Andrea Ciccotta
  • 598
  • 6
  • 16