5

How can I find the permutations of k in a given length?

For example:

The word cat has 3 letters: How can I find all the permutations of 2 in the word cat. Result should be: ac, at, ca, ac, etc...


This is not a homework problem. Any language could be used but more preferable: C/C++ or C#. I know how to create the recursion for size LENGTH but not for a custom size.

Y_Y
  • 1,259
  • 5
  • 26
  • 43
  • Any particular language? – Ignacio Vazquez-Abrams Feb 28 '10 at 05:38
  • 1
    Sounds like a homework problem. –  Feb 28 '10 at 05:39
  • Nope... Not homework problem and any language could be used but more preferable: C/C++ or C#. – Y_Y Feb 28 '10 at 05:40
  • I know how to create the recursion for size LENGHT but not for a custom size. – Y_Y Feb 28 '10 at 05:41
  • Do the partitions need to be lexicographic? – pestilence669 Feb 28 '10 at 05:59
  • Can the characters be repeated? I assume they can be... –  Feb 28 '10 at 07:30
  • Duplicate: http://stackoverflow.com/questions/1663949/how-do-i-get-all-permutations-of-xpy-in-c, http://stackoverflow.com/questions/127704/algorithm-to-return-all-combinations-of-k-elements-from-n – kennytm Feb 28 '10 at 07:34
  • 127704 is not dupe (it is about combinations, not permutations), and 1663949 does not seem to deal with repeated characters, though I would expect this would have been asked before. –  Feb 28 '10 at 07:37
  • @Moron: Who said characters can be repeated? There's no `aa` in the "results should be". – kennytm Feb 28 '10 at 07:46
  • 1
    @KennyTM: No. That is not what I meant. Since he seems to want english words, banana is valid input and so you should not duplicate aa in the output now (which the standard algorithm will). –  Feb 28 '10 at 14:49

6 Answers6

3

Here is one in C#, which should work even with repeated characters. For example on "banana" for permutations of length 2 it gives:

ba bn ab aa an nb na nn

The basic idea is to fix the first character, then form all permutations of length k-1, then prepend the character to those k-1 length permutations. To deal with duplicate characters, we keep track of the count left (i.e the ones which can be used for sub-permutations).

Not exemplary code, but should give you the idea. (If you find bugs, let me know and I can edit).

static List<string> Permutations(Dictionary<char, int> input, int length) {
    List<string> permutations = new List<string>();

    List<char> chars = new List<char>(input.Keys);

    // Base case.
    if (length == 0) {
        permutations.Add(string.Empty);
        return permutations;
    }

    foreach (char c in chars) {

        // There are instances of this character left to use.
        if (input[c] > 0) {

            // Use one instance up.
            input[c]--;

            // Find sub-permutations of length length -1.
            List<string> subpermutations = Permutations(input, length - 1);

            // Give back the instance.
            input[c]++;

            foreach (string s in subpermutations) {

                // Prepend the character to be the first character.
                permutations.Add(s.Insert(0,new string(c,1)));

            }
        }
    }

    return permutations;
}

And here is the full program I have, to use it:

using System;
using System.Collections.Generic;

namespace StackOverflow {

    class Program {
        static void Main(string[] args) {
            List<string> p = Permutations("abracadabra", 3);
            foreach (string s in p) {
                Console.WriteLine(s);
            }
        }

        static List<string> Permutations(string s, int length) {
            Dictionary<char, int> input = new Dictionary<char, int>();
            foreach (char c in s) {
                if (input.ContainsKey(c)) {
                    input[c]++;
                } else {
                    input[c] = 1;
                }
            }
            return Permutations(input, length);
        }

        static List<string> Permutations(Dictionary<char, int> input, 
                                                          int length) {
            List<string> permutations = new List<string>();

            List<char> chars = new List<char>(input.Keys);
            if (length == 0) {
                permutations.Add(string.Empty);
                return permutations;
            }

            foreach (char c in chars) {
                if (input[c] > 0) {
                    input[c]--;
                    List<string> subpermutations = Permutations(input, 
                                                                length - 1);
                    input[c]++;

                    foreach (string s in subpermutations) {
                        permutations.Add(s.Insert(0,new string(c,1)));
                    }
                }
            }

            return permutations;
        }
    }
}
  • @Y_Y: Glad it helped! It was fun to revisit this one after a long time. –  Mar 01 '10 at 08:05
2

What's wrong with the recursive solution and passing an extra parameter (depth) so that the recursive function returns immediately for depth > n.

ta.speot.is
  • 26,914
  • 8
  • 68
  • 96
1

Not the most efficient, but it works:

public class permutation
{
    public static List<string> getPermutations(int n, string word)
    {
        List<string> tmpPermutation = new List<string>();
        if (string.IsNullOrEmpty(word) || n <= 0)
        {
            tmpPermutation.Add("");
        }
        else
        {
            for (int i = 0; i < word.Length; i++)
            {
                string tmpWord = word.Remove(i, 1);
                foreach (var item in getPermutations(n - 1, tmpWord))
                {
                    tmpPermutation.Add(word[i] + item);
                }
            }
        }
        return tmpPermutation;
    }
}
Francisco
  • 4,104
  • 3
  • 24
  • 27
1
void Prem (char *str, int k, int length) {
    if (k == length-1){
         printf("%s\n",str);
         return;
    } else {
        for (int i = k ; i < length; ++i) {
            char t = str[k];
            str[k] = str[i];
            str[i] = t;
            Prem(str,k+1,length);
            t = str[k];
            str[k] = str[i];
            str[i] = t;
        }
    }
}
stealthyninja
  • 10,343
  • 11
  • 51
  • 59
0

If I'm not mistaken, this problem can be solved by combinadics too, as on http://en.wikipedia.org/wiki/Combinadic/, there are reference implementations there too.

I have used the Java solution (http://docs.google.com/Doc?id=ddd8c4hm_5fkdr3b/) myself for generating all possible triples from a sequence of numbers, this should be no different.

I lack the wherewithal to explain the math behind it, but as I understand this is the least complex way to iterate over all possible nCr (i.e. 3C2 for your cat example) choices within a collection.

Derek Mortimer
  • 1,061
  • 1
  • 8
  • 11
0

First find the possible subsets of your array. You can do this in a recursive way it was discussed in Iterating over subsets of any size

Second calculate the permutations of every subset with the STL-Algorithm next_permutation

I haven't implemented it but i think it should work.

Community
  • 1
  • 1
Christian Ammer
  • 7,464
  • 6
  • 51
  • 108