Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to generate a permutation?

My question is: given a list L of length n, and an integer i such that 0 <= i < n!, how can you write a function perm(L, n) to produce the ith permutation of L in O(n) time? What I mean by ith permutation is just the ith permutation in some implementation defined ordering that must have the properties:

  1. For any i and any 2 lists A and B, perm(A, i) and perm(B, i) must both map the jth element of A and B to an element in the same position for both A and B.

  2. For any inputs (A, i), (A, j) perm(A, i)==perm(A, j) if and only if i==j.

NOTE: this is not homework. In fact, I solved this 2 years ago, but I've completely forgotten how, and it's killing me. Also, here is a broken attempt I made at a solution:

def perm(s, i):
  n = len(s)
  perm = [0]*n
  itCount = 0
  for elem in s:
    perm[i%n + itCount] = elem
    i = i / n
    n -= 1
    itCount+=1
  return perm

ALSO NOTE: the O(n) requirement is very important. Otherwise you could just generate the n! sized list of all permutations and just return its ith element.

like image 423
CromTheDestroyer Avatar asked Nov 08 '10 01:11

CromTheDestroyer


People also ask

How do you calculate permutations?

The number of permutations of n objects taken r at a time is determined by the following formula: P(n,r)=n! (n−r)!

What is permutation generator?

This tool lists out all the arrangements possible using letters of a word under various conditions. This can be used to verify answers of the questions related to calculation of the number of arrangements using letters of a word. This tool programmatically generates all the arrangements possible.

How do you create all permutations of a set?

The number of permutations on a set of n elements is given by n!. For example, there are 2! = 2*1 = 2 permutations of {1, 2}, namely {1, 2} and {2, 1}, and 3! = 3*2*1 = 6 permutations of {1, 2, 3}, namely {1, 2, 3}, {1, 3, 2}, {2, 1, 3}, {2, 3, 1}, {3, 1, 2} and {3, 2, 1}.


2 Answers

def perm(sequence, index):
    sequence = list(sequence)
    result = []
    for x in xrange(len(sequence)):
        idx = index % len(sequence)
        index /= len(sequence)
        result.append( sequence[idx] )
        # constant time non-order preserving removal
        sequence[idx] = sequence[-1]
        del sequence[-1]
    return result

Based on the algorithm for shuffling, but we take the least significant part of the number each time to decide which element to take instead of a random number. Alternatively consider it like the problem of converting to some arbitrary base except that the base name shrinks for each additional digit.

like image 103
Winston Ewert Avatar answered Oct 06 '22 01:10

Winston Ewert


Could you use factoradics? You can find an illustration via this MSDN article.

Update: I wrote an extension of the MSDN algorithm that finds i'th permutation of n things taken r at a time, even if n != r.

like image 36
Joshua Ulrich Avatar answered Oct 06 '22 00:10

Joshua Ulrich