(0 <= i < n) of the k-th permutation (0 <= k < n!) of the sequence 0..n-1?What jkff said. You could modify an algorithm like the one you posted to just return the i-th element of the k-th permutation, but you won't save much time (or space), and you certainly won't reduce the Big-O complexity of the basic algorithm.
The unordered permutation code that you posted isn't really amenable to modification because it has to loop over all the elements performing its swaps, and it's painful to determine if it's possible to break out of the loop early.
However, there's a similar algorithm which produces ordered permutations, and it is possible to break out of that one early, but you still need to perform i inner loops to get the i-th element of the k-th permutation.
I've implemented this algorithm as a class, just to keep the various constants it uses tidy. The code below produces full permutations, but it should be easy to modify to just return the i-th element.
#!/usr/bin/env python
''' Ordered permutations using factorial base counting
Written by PM 2Ring 2015.02.15
Derived from C code written 2003.02.13
'''
from math import factorial
class Permuter(object):
''' A class for making ordered permutations, one by one '''
def __init__(self, seq):
self.seq = list(seq)
self.size = len(seq)
self.base = factorial(self.size - 1)
self.fac = self.size * self.base
def perm(self, k):
''' Build kth ordered permutation of seq '''
seq = self.seq[:]
p = []
base = self.base
for j in xrange(self.size - 1, 0, -1):
q, k = divmod(k, base)
p.append(seq.pop(q))
base //= j
p.append(seq[0])
return p
def test(seq):
permuter = Permuter(seq)
for k in xrange(permuter.fac):
print '%2d: %s' % (k, ''.join(permuter.perm(k)))
if __name__ == '__main__':
test('abcd')
This algorithm has a little more overhead than the unordered permutation maker: it requires factorial to be calculated in advance, and of course factorial gets very large very quickly. Also, it requires one extra division per inner loop. So the time savings in bailing out of the inner loop once you've found the i-th element may be offset by these overheads.
FWIW, the code in your question has room for improvement. In particular, k /= n should be written as k //= n to ensure that integer division is used; your code works ok on Python 2 but not on Python 3. However, since we need both the quotient and remainder, it makes sense to use the built-in divmod() function. Also, by reorganizing things a little we can avoid the multiple calculations of n - 1
#!/usr/bin/env python
def kth_permutation(n, k):
p = range(n)
while n:
k, j = divmod(k, n)
n -= 1
p[n], p[j] = p[j], p[n]
return p
def test(n):
last = range(n)
k = 0
while True:
p = kth_permutation(n, k)
print k, p
if p == last:
break
k += 1
test(3)
output
0 [1, 2, 0]
1 [2, 0, 1]
2 [1, 0, 2]
3 [2, 1, 0]
4 [0, 2, 1]
5 [0, 1, 2]
You probably cannot get the i'th digit of the k'th permutation of n elements in O(n) time or space, because representing the number k itself requires O(log(n!)) = O(n log n) bits, and any manipulations with it have corresponding time complexity.