Finding all the unique permutations of a string without generating duplicates

前端 未结 5 1589
轻奢々
轻奢々 2020-11-28 10:03

Finding all the permutations of a string is by a well known Steinhaus–Johnson–Trotter algorithm. But if the string contains the repeated characters such as
AABB,
the

相关标签:
5条回答
  • 2020-11-28 10:25

    Use the following recursive algorithm:

    PermutList Permute(SymArray fullSymArray){
        PermutList resultList=empty;
        for( each symbol A in fullSymArray, but repeated ones take only once) {
           PermutList lesserPermutList=  Permute(fullSymArray without A)
           for ( each SymArray item in lesserPermutList){
                resultList.add("A"+item);
           }
        }
        return resultList;
    }
    

    As you see, it is very easy

    0 讨论(0)
  • 2020-11-28 10:31

    I think this problem is essentially the problem of generating multiset permutations. this paper seems to be relevant: J. F. Korsh P. S. LaFollette. Loopless array generation of multiset permutations. The Computer Journal, 47(5):612–621, 2004.

    From the abstract: This paper presents a loopless algorithm to generate all permutations of a multiset. Each is obtained from its predecessor by making one transposition. It differs from previous such algorithms by using an array for the permutations but requiring storage only linear in its length.

    0 讨论(0)
  • 2020-11-28 10:35

    First convert the string to a set of unique characters and occurrence numbers e.g. BANANA -> (3, A),(1,B),(2,N). (This could be done by sorting the string and grouping letters). Then, for each letter in the set, prepend that letter to all permutations of the set with one less of that letter (note the recursion). Continuing the "BANANA" example, we have: permutations((3,A),(1,B),(2,N)) = A:(permutations((2,A),(1,B),(2,N)) ++ B:(permutations((3,A),(2,N)) ++ N:(permutations((3,A),(1,B),(1,N))

    Here is a working implementation in Haskell:

    circularPermutations::[a]->[[a]]
    circularPermutations xs = helper [] xs []
                              where helper acc [] _ = acc
                                    helper acc (x:xs) ys =
                                      helper (((x:xs) ++ ys):acc) xs (ys ++ [x])
    
    nrPermutations::[(Int, a)]->[[a]]
    nrPermutations x | length x == 1 = [take (fst (head x)) (repeat (snd (head x)))]
    nrPermutations xs = concat (map helper (circularPermutations xs))
      where helper ((1,x):xs) = map ((:) x)(nrPermutations xs)
            helper ((n,x):xs) = map ((:) x)(nrPermutations ((n - 1, x):xs))
    
    0 讨论(0)
  • 2020-11-28 10:40

    This is a tricky question and we need to use recursion to find all the permutations of a String, for example "AAB" permutations will be "AAB", "ABA" and "BAA". We also need to use Set to make sure there are no duplicate values.

    import java.io.*;
    import java.util.HashSet;
    import java.util.*;
    class Permutation {
    
        static HashSet<String> set = new HashSet<String>();
        public static void main (String[] args) {
        Scanner in = new Scanner(System.in);
            System.out.println("Enter :");
            StringBuilder  str = new StringBuilder(in.nextLine());
            NONDuplicatePermutation("",str.toString());  //WITHOUT DUPLICATE PERMUTATION OF STRING
            System.out.println(set);
        }
    
    
        public static void NONDuplicatePermutation(String prefix,String str){
            //It is nlogn
            if(str.length()==0){
                set.add(prefix);
            }else{
                for(int i=0;i<str.length();i++){
    
                    NONDuplicatePermutation(prefix+ str.charAt(i), str.substring(0,i)+str.substring(i+1));
                }
            }
    
        }
    
    }
    
    0 讨论(0)
  • 2020-11-28 10:47

    In my solution, I generate recursively the options, try every time to add every letter that I didn't use as many times I need yet.

    #include <string.h>
    
    void fill(char ***adr,int *pos,char *pref) {
        int i,z=1;
        //loop on the chars, and check if should use them
        for (i=0;i<256;i++)
            if (pos[i]) {
                int l=strlen(pref);
                //add the char
                pref[l]=i;
                pos[i]--;
                //call the recursion
                fill(adr,pos,pref);
                //delete the char
                pref[l]=0;
                pos[i]++;
                z=0;
            }
        if (z) strcpy(*(*adr)++,pref);
    }
    
    void calc(char **arr,const char *str) {
        int p[256]={0};
        int l=strlen(str);
        char temp[l+1];
        for (;l>=0;l--) temp[l]=0;
        while (*str) p[*str++]++;
        fill(&arr,p,temp);
    }
    

    use example:

    #include <stdio.h>
    #include <string.h>
    
    int main() {
        char s[]="AABAF";
        char *arr[20];
        int i;
        for (i=0;i<20;i++) arr[i]=malloc(sizeof(s));
        calc(arr,s);
        for (i=0;i<20;i++) printf("%d: %s\n",i,arr[i]);
        return 0;
    }
    
    0 讨论(0)
提交回复
热议问题