Question

I ai n éléments. Par souci d'un exemple, disons, 7 éléments, 1234567. Je sais qu'il ya 7! = 5040 permutations possibles de ces 7 éléments.

Je veux un algorithme rapide comprenant deux fonctions:

f (nombre) fait correspondre un nombre compris entre 0 et 5039 à une permutation unique, et

f '(permutation) mappe la permutation vers le numéro qui lui a été généré à partir de.

Je ne se soucient pas de la correspondance entre le nombre et la permutation, fournissant chaque permutation a son propre numéro unique.

Ainsi, par exemple, je pourrais avoir des fonctions où

f(0) = '1234567'
f'('1234567') = 0

L'algorithme le plus rapide qui vient à l'esprit est d'énumérer toutes les permutations et de créer une table de consultation dans les deux sens, de sorte que, une fois les tables sont créées, f (0) serait O (1) et f ( « 1234567 ») serait une recherche sur une chaîne. Cependant, cette mémoire est faim, surtout quand n devient grand.

Quelqu'un peut-il proposer un autre algorithme qui fonctionnerait rapidement et sans l'inconvénient de la mémoire?

Était-ce utile?

La solution

Pour décrire une permutation des n éléments, vous voyez que pour la position que le premier élément se termine à, vous avez n possibilités, de sorte que vous pouvez décrire cela avec un nombre compris entre 0 et n-1. Pour la position que l'élément suivant se termine à, vous avez n-1 possibilités restantes, de sorte que vous pouvez décrire cela avec un nombre compris entre 0 et n-2.
Et ainsi de suite jusqu'à ce que vous avez n chiffres.

A titre d'exemple pour n = 5, considérez la permutation qui apporte abcde à caebd.

  • a, le premier élément, se termine à la seconde position, de sorte que nous assigner index 1 .
  • b se termine à la quatrième position, ce qui serait l'indice 3, mais il est le troisième restant, donc nous lui assigner 2 .
  • c se termine à la première position restante, qui est toujours 0 .
  • d se termine à la dernière position restante qui (sur seulement deux positions restantes) est 1 .
  • e se termine à la position restante seulement, indexé à 0 .

Nous avons donc la séquence d'index {1, 2, 0, 1, 0} .

Maintenant, vous savez que, par exemple, dans un nombre binaire, « xyz » signifie z + 2y + 4x. Pour un nombre décimal,
il est z + 10Y + 100x. Chaque chiffre est multiplié par un peu de poids, et les résultats sont additionnés. Le motif évident dans le poids est bien entendu que le poids est w = b ^ k, avec b la base du nombre et k l'indice du chiffre. (Je toujours compter les chiffres de droite et à partir de l'index 0 pour le chiffre le plus à droite. De même quand je parle de la « première » chiffres que je veux dire à l'extrême droite.)

raison pourquoi les poids pour les chiffres suivent ce modèle est que le plus grand nombre qui peut être représenté par les chiffres de 0 à k doit être exactement 1 inférieur au nombre le plus bas qui peut être représenté par uniquement à l'aide chiffre k + 1. En binaire, 0111 doit être inférieure à un 1000. En décimal, 099999 doit être l'une inférieure à 100000.

encodage à base variable L'espacement entre les numéros suivants étant exactement 1 est la règle importante. En réalisant cela, nous pouvons représenter notre séquence d'index par un numéro base variable . La base pour chaque chiffre est le montant des différentes possibilités de ce chiffre. Pour chaque chiffre décimal a 10 possibilités, pour notre système, le chiffre d'extrême droite aurait une possibilité et le plus à gauche aura n possibilités. Mais depuis le chiffre le plus à droite (le dernier numéro dans notre séquence) est toujours 0, nous laissons sortir. Cela signifie que nous nous retrouvons avec des bases 2 à n. En général, le chiffre kème aura base b [k] = k + 2. La valeur la plus élevée autorisée pour le chiffre k est h [k] = b [k] -. 1 = k + 1

Notre règle sur les poids w [k] de chiffres exige que la somme de h [i] * w [i], où i va de i = 0 à i = k, est égale à 1 * w [k + 1]. Dit de manière récurrente, w [k + 1] = w [k] + h [k] * w [k] = p [k] * (h [k] + 1). doit toujours le premier poids w [0] être 1. A partir de là, nous avons les valeurs suivantes:

k    h[k] w[k]    

0    1    1  
1    2    2    
2    3    6    
3    4    24   
...  ...  ...
n-1  n    n!  

(La relation générale w [k-1] = k! Est facilement démontrée par induction).

Le nombre que nous recevons de la conversion de notre séquence sera alors la somme de s [k] * w [k], k allant de 0 à n-1. Ici s [k] est l'élément k-ième (à droite, à partir de 0) de la séquence. À titre d'exemple, prendre notre {1, 2, 0, 1, 0}, l'élément le plus à droite éliminé comme mentionné précédemment: {1, 2, 0, 1} . Notre somme est 1 * 1 + 0 * 2 + 2 * 6 + 1 * 24 = 37 .

Notez que si nous prenons la position maximale pour tous les indices, nous aurions {4, 3, 2, 1, 0}, et qui convertit à 119. Comme les poids dans notre encodage nombre ont été choisis de telle sorte que nous don « t sauter des chiffres, tous les numéros 0 à 119 sont valides. Il y a précisément 120 d'entre eux, qui est n! pour n = 5 dans notre exemple, précisément le nombre de permutations différentes. Ainsi, vous pouvez voir nos numéros codés spécifient complètement toutes les permutations possibles.

Décodage de base variable Le décodage est similaire à la conversion en binaire ou décimal. L'algorithme commun est le suivant:

int number = 42;
int base = 2;
int[] bits = new int[n];

for (int k = 0; k < bits.Length; k++)
{
    bits[k] = number % base;
    number = number / base;
}

Pour notre numéro base variable:

int n = 5;
int number = 37;

int[] sequence = new int[n - 1];
int base = 2;

for (int k = 0; k < sequence.Length; k++)
{
    sequence[k] = number % base;
    number = number / base;

    base++; // b[k+1] = b[k] + 1
}

Ce correctement décode notre 37 retour à {1, 2, 0, 1} (sequence serait {1, 0, 2, 1} dans cet exemple de code, mais peu importe ... tant que vous indexez correctement). Nous avons juste besoin d'ajouter 0 à l'extrémité droite (rappelez-vous le dernier élément a toujours qu'une seule possibilité pour sa nouvelle position) pour revenir à notre séquence d'origine {1, 2, 0, 1, 0}.

permutant une liste à l'aide d'une séquence d'index Vous pouvez utiliser l'algorithme ci-dessous pour une liste permute selon une séquence d'index spécifique. Il est un algorithme O (n²), malheureusement.

int n = 5;
int[] sequence = new int[] { 1, 2, 0, 1, 0 };
char[] list = new char[] { 'a', 'b', 'c', 'd', 'e' };
char[] permuted = new char[n];
bool[] set = new bool[n];

for (int i = 0; i < n; i++)
{
    int s = sequence[i];
    int remainingPosition = 0;
    int index;

    // Find the s'th position in the permuted list that has not been set yet.
    for (index = 0; index < n; index++)
    {
        if (!set[index])
        {
            if (remainingPosition == s)
                break;

            remainingPosition++;
        }
    }

    permuted[index] = list[i];
    set[index] = true;
}

Représentation commune des permutations Normalement, vous ne représenterait pas une permutation comme unintuitively comme nous l'avons fait, mais simplement par la position absolue de chaque élément après la permutation est appliquée. Notre exemple {1, 2, 0, 1, 0} pour abcde à caebd est normalement représenté par {1, 3, 0, 4, 2}. Chaque indice de 0 à 4 (ou en général, de 0 à n-1) se produit exactement une fois dans cette représentation.

L'application d'une permutation sous cette forme est facile:

int[] permutation = new int[] { 1, 3, 0, 4, 2 };

char[] list = new char[] { 'a', 'b', 'c', 'd', 'e' };
char[] permuted = new char[n];

for (int i = 0; i < n; i++)
{
    permuted[permutation[i]] = list[i];
}

est très inversant similaire:

for (int i = 0; i < n; i++)
{
    list[i] = permuted[permutation[i]];
}

La conversion de notre représentation à la représentation commune Notez que si nous prenons notre algorithme pour permute une liste à l'aide de notre séquence d'index, et l'appliquer à la permutation d'identité {0, 1, 2, ..., n-1}, nous obtenons la inverse permutation, représentée sous la forme commune. ( {2, 0, 4, 1, 3} dans notre exemple).

Pour obtenir la premutation non inversée, on applique l'algorithme de permutation Je viens montré:

int[] identity = new int[] { 0, 1, 2, 3, 4 };
int[] inverted = { 2, 0, 4, 1, 3 };
int[] normal = new int[n];

for (int i = 0; i < n; i++)
{
    normal[identity[i]] = list[i];
}

Ou vous pouvez simplement appliquer la permutation directement, en utilisant l'algorithme de permutation inverse:

char[] list = new char[] { 'a', 'b', 'c', 'd', 'e' };
char[] permuted = new char[n];

int[] inverted = { 2, 0, 4, 1, 3 };

for (int i = 0; i < n; i++)
{
    permuted[i] = list[inverted[i]];
}

Notez que tous les algorithmes de traitement des permutations dans la forme commune sont O (n), tout en appliquant une permutation dans notre forme est O (n²). Si vous avez besoin d'appliquer une permutation à plusieurs reprises, d'abord le convertir à la représentation commune.

Autres conseils

Je l'ai trouvé un algorithme O (n), voici une brève explication http://antoinecomeau.blogspot.ca/2014/07/mapping-between-permutations-and.html

public static int[] perm(int n, int k)
{
    int i, ind, m=k;
    int[] permuted = new int[n];
    int[] elems = new int[n];

    for(i=0;i<n;i++) elems[i]=i;

    for(i=0;i<n;i++)
    {
            ind=m%(n-i);
            m=m/(n-i);
            permuted[i]=elems[ind];
            elems[ind]=elems[n-i-1];
    }

    return permuted;
}

public static int inv(int[] perm)
{
    int i, k=0, m=1;
    int n=perm.length;
    int[] pos = new int[n];
    int[] elems = new int[n];

    for(i=0;i<n;i++) {pos[i]=i; elems[i]=i;}

    for(i=0;i<n-1;i++)
    {
            k+=m*pos[perm[i]];
            m=m*(n-i);
            pos[elems[n-i-1]]=pos[perm[i]];
            elems[pos[perm[i]]]=elems[n-i-1];
    }

    return k;
}

La complexité peut être ramené à n * log (n), voir la section 10.1.1 ( "Le code Lehmer (table d'inversion)", p.232ff) de la fxtbook:    http://www.jjj.de/fxt/#fxtbook passez à la section 10.1.1.1 ( « Calcul avec de grands tableaux » p.235) pour la méthode rapide. Le (sous licence GPL, C ++) code se trouve sur la même page Web.

Chaque élément peut être dans l'un des sept postes. Pour décrire la position d'un élément, vous auriez besoin trois bits. Cela signifie que vous pouvez stocker la position de tous les éléments d'une valeur de 32 bits. C'est loin d'être efficace, puisque cette représentation serait même que tous les éléments soient dans la même position, mais je crois que devrait être assez rapide le masquage de bits.

Cependant, avec plus de 8 positions, vous aurez besoin de quelque chose plus astucieux.

Cela arrive à être une fonction intégrée J :

   A. 1 2 3 4 5 6 7
0
   0 A. 1 2 3 4 5 6 7
1 2 3 4 5 6 7

   ?!7
5011
   5011 A. 1 2 3 4 5 6 7
7 6 4 5 1 3 2
   A. 7 6 4 5 1 3 2
5011

Problème résolu. Cependant, je ne suis pas sûr que vous avez encore besoin de la solution après ces années. LOL, je viens de rejoindre ce site, donc ... Vérifiez ma classe Java Permutation. Vous pouvez baser sur un index pour obtenir une permutation de symboles, ou donner une permutation de symboles puis obtenir l'indice.

Voici ma classe prémutations

/**
 ****************************************************************************************************************
 * Copyright 2015 Fred Pang fred@pnode.com
 ****************************************************************************************************************
 * A complete list of Permutation base on an index.
 * Algorithm is invented and implemented by Fred Pang fred@pnode.com
 * Created by Fred Pang on 18/11/2015.
 ****************************************************************************************************************
 * LOL this is my first Java project. Therefore, my code is very much like C/C++. The coding itself is not
 * very professional. but...
 *
 * This Permutation Class can be use to generate a complete list of all different permutation of a set of symbols.
 * nPr will be n!/(n-r)!
 * the user can input       n = the number of items,
 *                          r = the number of slots for the items,
 *                          provided n >= r
 *                          and a string of single character symbols
 *
 * the program will generate all possible permutation for the condition.
 *
 * Say if n = 5, r = 3, and the string is "12345", it will generate sll 60 different permutation of the set
 * of 3 character strings.
 *
 * The algorithm I used is base on a bin slot.
 * Just like a human or simply myself to generate a permutation.
 *
 * if there are 5 symbols to chose from, I'll have 5 bin slot to indicate which symbol is taken.
 *
 * Note that, once the Permutation object is initialized, or after the constructor is called, the permutation
 * table and all entries are defined, including an index.
 *
 * eg. if pass in value is 5 chose 3, and say the symbol string is "12345"
 * then all permutation table is logically defined (not physically to save memory).
 * It will be a table as follows
 *  index  output
 *      0   123
 *      1   124
 *      2   125
 *      3   132
 *      4   134
 *      5   135
 *      6   143
 *      7   145
 *      :     :
 *      58  542
 *      59  543
 *
 * all you need to do is call the "String PermGetString(int iIndex)" or the "int[] PermGetIntArray(int iIndex)"
 * function or method with an increasing iIndex, starting from 0 to getiMaxIndex() - 1. It will return the string
 * or the integer array corresponding to the index.
 *
 * Also notice that in the input string is "12345" of  position 01234, and the output is always in accenting order
 * this is how the permutation is generated.
 *
 * ***************************************************************************************************************
 * ====  W a r n i n g  ====
 * ***************************************************************************************************************
 *
 * There is very limited error checking in this class
 *
 * Especially the  int PermGetIndex(int[] iInputArray)  method
 * if the input integer array contains invalid index, it WILL crash the system
 *
 * the other is the string of symbol pass in when the object is created, not sure what will happen if the
 * string is invalid.
 * ***************************************************************************************************************
 *
 */
public class Permutation
{
    private boolean bGoodToGo = false;      // object status
    private boolean bNoSymbol = true;
    private BinSlot slot;                   // a bin slot of size n (input)
    private int nTotal;                     // n number for permutation
    private int rChose;                     // r position to chose
    private String sSymbol;                 // character string for symbol of each choice
    private String sOutStr;
    private int iMaxIndex;                  // maximum index allowed in the Get index function
    private int[] iOutPosition;             // output array
    private int[] iDivisorArray;            // array to do calculation

    public Permutation(int inCount, int irCount, String symbol)
    {
        if (inCount >= irCount)
        {
            // save all input values passed in
            this.nTotal = inCount;
            this.rChose = irCount;
            this.sSymbol = symbol;

            // some error checking
            if (inCount < irCount || irCount <= 0)
                return;                                 // do nothing will not set the bGoodToGo flag

            if (this.sSymbol.length() >= inCount)
            {
                bNoSymbol = false;
            }

            // allocate output storage
            this.iOutPosition = new int[this.rChose];

            // initialize the bin slot with the right size
            this.slot = new BinSlot(this.nTotal);

            // allocate and initialize divid array
            this.iDivisorArray = new int[this.rChose];

            // calculate default values base on n & r
            this.iMaxIndex = CalPremFormula(this.nTotal, this.rChose);

            int i;
            int j = this.nTotal - 1;
            int k = this.rChose - 1;

            for (i = 0; i < this.rChose; i++)
            {
                this.iDivisorArray[i] = CalPremFormula(j--, k--);
            }
            bGoodToGo = true;       // we are ready to go
        }
    }

    public String PermGetString(int iIndex)
    {
        if (!this.bGoodToGo) return "Error: Object not initialized Correctly";
        if (this.bNoSymbol) return "Error: Invalid symbol string";
        if (!this.PermEvaluate(iIndex)) return "Invalid Index";

        sOutStr = "";
        // convert string back to String output
        for (int i = 0; i < this.rChose; i++)
        {
            String sTempStr = this.sSymbol.substring(this.iOutPosition[i], iOutPosition[i] + 1);
            this.sOutStr = this.sOutStr.concat(sTempStr);
        }
        return this.sOutStr;
    }

    public int[] PermGetIntArray(int iIndex)
    {
        if (!this.bGoodToGo) return null;
        if (!this.PermEvaluate(iIndex)) return null ;
        return this.iOutPosition;
    }

    // given an int array, and get the index back.
    //
    //  ====== W A R N I N G ======
    //
    // there is no error check in the array that pass in
    // if any invalid value in the input array, it can cause system crash or other unexpected result
    //
    // function pass in an int array generated by the PermGetIntArray() method
    // then return the index value.
    //
    // this is the reverse of the PermGetIntArray()
    //
    public int PermGetIndex(int[] iInputArray)
    {
        if (!this.bGoodToGo) return -1;
        return PermDoReverse(iInputArray);
    }


    public int getiMaxIndex() {
    return iMaxIndex;
}

    // function to evaluate nPr = n!/(n-r)!
    public int CalPremFormula(int n, int r)
    {
        int j = n;
        int k = 1;
        for (int i = 0; i < r; i++, j--)
        {
            k *= j;
        }
        return k;
    }


//  PermEvaluate function (method) base on an index input, evaluate the correspond permuted symbol location
//  then output it to the iOutPosition array.
//
//  In the iOutPosition[], each array element corresponding to the symbol location in the input string symbol.
//  from location 0 to length of string - 1.

    private boolean PermEvaluate(int iIndex)
    {
        int iCurrentIndex;
        int iCurrentRemainder;
        int iCurrentValue = iIndex;
        int iCurrentOutSlot;
        int iLoopCount;

        if (iIndex >= iMaxIndex)
            return false;

        this.slot.binReset();               // clear bin content
        iLoopCount = 0;
        do {
            // evaluate the table position
            iCurrentIndex = iCurrentValue / this.iDivisorArray[iLoopCount];
            iCurrentRemainder = iCurrentValue % this.iDivisorArray[iLoopCount];

            iCurrentOutSlot = this.slot.FindFreeBin(iCurrentIndex);     // find an available slot
            if (iCurrentOutSlot >= 0)
                this.iOutPosition[iLoopCount] = iCurrentOutSlot;
            else return false;                                          // fail to find a slot, quit now

            this.slot.setStatus(iCurrentOutSlot);                       // set the slot to be taken
            iCurrentValue = iCurrentRemainder;                          // set new value for current value.
            iLoopCount++;                                               // increase counter
        } while (iLoopCount < this.rChose);

        // the output is ready in iOutPosition[]
        return true;
    }

    //
    // this function is doing the reverse of the permutation
    // the input is a permutation and will find the correspond index value for that entry
    // which is doing the opposit of the PermEvaluate() method
    //
    private int PermDoReverse(int[] iInputArray)
    {
        int iReturnValue = 0;
        int iLoopIndex;
        int iCurrentValue;
        int iBinLocation;

        this.slot.binReset();               // clear bin content

        for (iLoopIndex = 0; iLoopIndex < this.rChose; iLoopIndex++)
        {
            iCurrentValue = iInputArray[iLoopIndex];
            iBinLocation = this.slot.BinCountFree(iCurrentValue);
            this.slot.setStatus(iCurrentValue);                          // set the slot to be taken
            iReturnValue = iReturnValue + iBinLocation * this.iDivisorArray[iLoopIndex];
        }
        return iReturnValue;
    }


    /*******************************************************************************************************************
     *******************************************************************************************************************
     * Created by Fred on 18/11/2015.   fred@pnode.com
     *
     * *****************************************************************************************************************
     */
    private static class BinSlot
    {
        private int iBinSize;       // size of array
        private short[] eStatus;    // the status array must have length iBinSize

        private BinSlot(int iBinSize)
        {
            this.iBinSize = iBinSize;               // save bin size
            this.eStatus = new short[iBinSize];     // llocate status array
        }

        // reset the bin content. no symbol is in use
        private void binReset()
        {
            // reset the bin's content
            for (int i = 0; i < this.iBinSize; i++) this.eStatus[i] = 0;
        }

        // set the bin position as taken or the number is already used, cannot be use again.
        private void  setStatus(int iIndex) { this.eStatus[iIndex]= 1; }

        //
        // to search for the iIndex th unused symbol
        // this is important to search through the iindex th symbol
        // because this is how the table is setup. (or the remainder means)
        // note: iIndex is the remainder of the calculation
        //
        // for example:
        // in a 5 choose 3 permutation symbols "12345",
        // the index 7 item (count starting from 0) element is "1 4 3"
        // then comes the index 8, 8/12 result 0 -> 0th symbol in symbol string = '1'
        // remainder 8. then 8/3 = 2, now we need to scan the Bin and skip 2 unused bins
        //              current the bin looks 0 1 2 3 4
        //                                    x o o o o     x -> in use; o -> free only 0 is being used
        //                                      s s ^       skipped 2 bins (bin 1 and 2), we get to bin 3
        //                                                  and bin 3 is the bin needed. Thus symbol "4" is pick
        // in 8/3, there is a remainder 2 comes in this function as 2/1 = 2, now we have to pick the empty slot
        // for the new 2.
        // the bin now looks 0 1 2 3 4
        //                   x 0 0 x 0      as bin 3 was used by the last value
        //                     s s   ^      we skip 2 free bins and the next free bin is bin 4
        //                                  therefor the symbol "5" at the symbol array is pick.
        //
        // Thus, for index 8  "1 4 5" is the symbols.
        //
        //
        private int FindFreeBin(int iIndex)
        {
            int j = iIndex;

            if (j < 0 || j > this.iBinSize) return -1;               // invalid index

            for (int i = 0; i < this.iBinSize; i++)
            {
                if (this.eStatus[i] == 0)       // is it used
                {
                    // found an empty slot
                    if (j == 0)                 // this is a free one we want?
                        return i;               // yes, found and return it.
                    else                        // we have to skip this one
                        j--;                    // else, keep looking and count the skipped one
                }
            }
            assert(true);           // something is wrong
            return -1;              // fail to find the bin we wanted
        }

        //
        // this function is to help the PermDoReverse() to find out what is the corresponding
        // value during should be added to the index value.
        //
        // it is doing the opposite of int FindFreeBin(int iIndex) method. You need to know how this
        // FindFreeBin() works before looking into this function.
        //
        private int BinCountFree(int iIndex)
        {
            int iRetVal = 0;
            for (int i = iIndex; i > 0; i--)
            {
                if (this.eStatus[i-1] == 0)       // it is free
                {
                    iRetVal++;
                }
            }
            return iRetVal;
        }
    }
}
// End of file - Permutation.java

et voici ma classe principale pour montrer comment utiliser la classe.

/*
 * copyright 2015 Fred Pang
 *
 * This is the main test program for testing the Permutation Class I created.
 * It can be use to demonstrate how to use the Permutation Class and its methods to generate a complete
 * list of a permutation. It also support function to get back the index value as pass in a permutation.
 *
 * As you can see my Java is not very good. :)
 * This is my 1st Java project I created. As I am a C/C++ programmer for years.
 *
 * I still have problem with the Scanner class and the System class.
 * Note that there is only very limited error checking
 *
 *
 */

import java.util.Scanner;

public class Main
{
    private static Scanner scanner = new Scanner(System.in);

    public static void main(String[] args)
    {
        Permutation perm;       // declear the object
        String sOutString = "";
        int nCount;
        int rCount;
        int iMaxIndex;

        // Get user input
        System.out.println("Enter n: ");
        nCount = scanner.nextInt();

        System.out.println("Enter r: ");
        rCount = scanner.nextInt();

        System.out.println("Enter Symbol: ");
        sOutString = scanner.next();

        if (sOutString.length() < rCount)
        {
            System.out.println("String too short, default to numbers");
            sOutString = "";
        }

        // create object with user requirement
        perm = new Permutation(nCount, rCount, sOutString);

        // and print the maximum count
        iMaxIndex = perm.getiMaxIndex();
        System.out.println("Max count is:" + iMaxIndex);

        if (!sOutString.isEmpty())
        {
            for (int i = 0; i < iMaxIndex; i++)
            {   // print out the return permutation symbol string
                System.out.println(i + " " + perm.PermGetString(i));
            }
        }
        else
        {
            for (int i = 0; i < iMaxIndex; i++)
            {
                System.out.print(i + " ->");

                // Get the permutation array
                int[] iTemp = perm.PermGetIntArray(i);

                // print out the permutation
                for (int j = 0; j < rCount; j++)
                {
                    System.out.print(' ');
                    System.out.print(iTemp[j]);
                }

                // to verify my PermGetIndex() works. :)
                if (perm.PermGetIndex(iTemp)== i)
                {
                    System.out.println(" .");
                }
                else
                {   // oops something is wrong :(
                    System.out.println(" ***************** F A I L E D *************************");
                    assert(true);
                    break;
                }
            }
        }
    }
}
//
// End of file - Main.java

Amusez-vous. :)

Vous pouvez encoder des permutations en utilisant un algorithme récursif. Si une N-permutation (un certain ordre des nombres {0, .., N-1}) est de la forme {x, ...} encoder ensuite comme x + N * le codage de la (N-1) -permutation représenté par "..." sur les chiffres {0, N-1} - {x}. Sonne comme une bouchée, voici un code:

// perm[0]..perm[n-1] must contain the numbers in {0,..,n-1} in any order.
int permToNumber(int *perm, int n) {
  // base case
  if (n == 1) return 0;

  // fix up perm[1]..perm[n-1] to be a permutation on {0,..,n-2}.
  for (int i = 1; i < n; i++) {
    if (perm[i] > perm[0]) perm[i]--;
  }

  // recursively compute
  return perm[0] + n * permToNumber(perm + 1, n - 1);
}

// number must be >=0, < n!
void numberToPerm(int number, int *perm, int n) {
  if (n == 1) {
    perm[0] = 0;
    return;
  }
  perm[0] = number % n;
  numberToPerm(number / n, perm + 1, n - 1);

  // fix up perm[1] .. perm[n-1]
  for (int i = 1; i < n; i++) {
    if (perm[i] >= perm[0]) perm[i]++;
  }
}

Cet algorithme est O (n ^ 2). Les points de bonus si quelqu'un a un algorithme de O (n).

Quelle question intéressante!

Si tous vos éléments sont des nombres, vous voudrez peut-être envisager de les convertir de chaînes en nombres réels. Ensuite, vous pourrez trier toutes les permutations en les mettant dans l'ordre, et les placer dans un tableau. Après cela, vous seriez ouvert à l'un des différents algorithmes de là-bas LA RECHERCHE.

Je suis précipitée dans ma réponse précédente (supprimé), je n'ai la réponse réelle cependant. Il est fourni par un concept similaire, le factoradic , et est liée aux permutations (ma réponse connexe à des combinaisons, je présente mes excuses pour cette confusion). Je déteste juste après les liens wikipedia, mais je WriteUp je l'ai fait il y a quelque temps est incompréhensible pour une raison quelconque. Donc, je peux développer plus tard si nécessaire.

Il y a un livre écrit à ce sujet. Désolé, mais je ne me rappelle pas le nom de celui-ci (vous trouverez assez probablement de wikipedia). mais de toute façon je l'ai écrit une implémentation Python de ce système d'énumération: http://kks.cabal.fi/Kombinaattori Certaines d'entre elles est en finnois, mais il suffit de copier les variables de code et le nom ...

Une question connexe est calcul de la permutation inverse, une permutation qui rétablira les vecteurs permutés à l'ordre d'origine lorsque seule la matrice de permutation est connue. Voici le code O (n) (en PHP):

// Compute the inverse of a permutation
function GetInvPerm($Perm)
    {
    $n=count($Perm);
    $InvPerm=[];
    for ($i=0; $i<$n; ++$i)
        $InvPerm[$Perm[$i]]=$i;
    return $InvPerm;
    } // GetInvPerm

David Spector Logiciel Springtime

J'ai eu cette question exacte et je pensais que je fournirais ma solution Python. Il est O (n ^ 2).

import copy

def permute(string, num):
    ''' generates a permutation '''
    def build_s(factoradic): # Build string from factoradic in list form
        string0 = copy.copy(string)
        n = []
        for i in range(len(factoradic)):
            n.append(string0[factoradic[i]])
            del string0[factoradic[i]]
        return n

    f = len(string)
    factoradic = []
    while(f != 0): # Generate factoradic number list
        factoradic.append(num % f)
        num = (num - factoradic[-1])//f
        f -= 1

    return build_s(factoradic)

s = set()
# Print 120 permutations of this string
for i in range(120):
    m = permute(list('abcde'), i)
    s.add(''.join(m))

print(len(s)) # Check that we have 120 unique permutations

Il est assez simple; après avoir généré la représentation factoradic du nombre, je viens de ramasser et de supprimer les caractères de la chaîne. La suppression de la chaîne est la raison pour laquelle cette solution est O (n ^ 2).

La solution d'Antoine est meilleur pour la performance.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top