---
title: Permutation Sequence
date: 2022-06-23
tags: ["permutation", "recursion"]
canonical: https://invariant.khalilli.ai/blog/permutation-sequence/
license: CC BY-SA 4.0
---

> **Problem:** The set [1, 2, 3, ..., n] contains a total of n! unique permutations. Given n and k, return the kth permutation sequence.



This problem is really cool and helpful to gain intuition on permutation problems.
Both recursive and iterative approaches are actually similar, but I will explain recursive approach, because it's much more native way for this problem.
**Core idea here is**: think the problem recursively as,

<p align="center">
<img align="center" width="300" src="https://invariant.khalilli.ai/images/external/e94c869454-d348f993-4745-4e74-9d18-d92310a9eff5_1655981576.235183.png" alt="permutation sequence">
<img align="center"  width="400" height="400" src="https://invariant.khalilli.ai/images/external/707d1b7563-3243d922-7791-45c3-8376-5d2e74e9ebce_1655981374.6659791.png" alt="permutation sequence">
</p>
> **Theorem:** Proof: Initially for the first index of number, there are n! options. K initially resides in [1...K...N!] range. But for each number, there is block_size. What is this block size? Block size is it's (for each number) total number of contributions on current index to the permutations.
> Initially there are n numbers available as a choice. For next id there are n-1, for next after next there are n-2 etc.. You can think about that as a pigeon-hole principle. <br/>
> 
> **0. For the 0th state:** n! is the initial block size [this state is abstact]<br/>
> **1. For the first index:** prev_block_size / n -> n!/n<br/>
> **2. For the second index:** prev_block_size / n-1 -> n!/n*(n-1)<br/>
> **3. For the third index:** prev_block_size/(n-2) -> n! / n * (n-1) \* (n-2)<br/>
> ...

![figure](https://invariant.khalilli.ai/images/external/1a7d7a914b-7dc60874-f93d-4ead-8269-d25d85242c81_1655981703.6124957.png)

**To find k, n, block_size for the next recursive state?**

> **Approach:** 1. new k will be k % curr_block_size (you can clearly see it from the pictures above). new k for the next recursive part will reside within borders of the previous block.
> 2. next n will be, n-1. will also delete n from the selection space.
> 3. new block_size will be, previous_block_size / new_space

```python
class Solution:
    def getPermutation(self, n: int, k: int) -> str:
        return self.solve(n, k)

    def solve(self, n, k):
        '''
            123
            132

            213
            231

            312
            321

            how many permutations?
            n * (n-1) * (n-2) [main range]

            main range: 1...n!
            main blocksize: n!//n (for example: 3 numbers, 3! permutations, 3!//3 block size)
            main formula: block_size * numbers = permutationsize

            second range: 1...(n-1)!
            second blocksize:
            second formula: block_size * (n-1) = (n-1)!


            K ?

            1.... K .... n!

            (k // block_size + 1) -> number
            k % block_size -> new_k (for remaining partition)
            initial_block_size = n!

            [2,3,1]

        '''
        import math

        nums = [i for i in range(1, n+1)]

        def recurse(n, k, block_size, res):
            if n == 0:
                return res

            block_size = block_size // n
            numidx = k // block_size
            res += str(nums[numidx])
            del nums[numidx]
            return recurse(n-1, k % block_size, block_size, res)

        return recurse(n, k-1, math.factorial(n), '')
```

<br/>

**Further Research**

- Make research about the factorial number system
![figure](https://invariant.khalilli.ai/images/external/a142b18ee5-index.png)
