1. 题目

The set [1,2,3,…,n] contains a total of n! unique permutations.

By listing and labeling all of the permutations in order,
We get the following sequence (ie, for n = 3):

"123"
"132"
"213"
"231"
"312"
"321"
Given n and k, return the kth permutation sequence.

Note: Given n will be between 1 and 9 inclusive.

2. 思路

m个数字的排列形式有m!种。
对N个数排序,按数字序排序下,求k-th序列位的排列形式。
从小往大。因此,如果(N-1)可以排下,则前一位先直接排最小的,然后剩下的再去拍到k序来。
当k在i!和i(i-1)!的的范围内时,用后i个数字来拍。每次先看用i-1个可以排除多少种。然后看k是几个(i-1)!的大小,下一个数字就是剩下待排的第几位。
由于排列是用1开始的,而我们的计算是从0开始的,因此先减去一个1.

BTW:用递归求解更简单。

3. 代码

耗时:3ms

class Solution {
public:
    Solution() {
        p[0] = 1;
        for (int i = 1; i < 10; i++) {
            p[i] = p[i-1] * i;
        }
    }
    // n个数字最多有n!种, i个数字有i!种
    // 如果k的范围在(i-1)!和i!之间, 则表示只需要i个数字进行排列,剩下的n-i个数字选择("123..n-i"的前缀)
    // 如果是j个数字进行排列,则在看k是(j-1)!的x倍,则下一位是第x位的字符,依次往下
    string getPermutation(int n, int k) {
        string ret;
        if (k > p[n]) return ret;
        int pos = 1;
        for (; pos < 10; pos++) {
            if (p[pos] >= k) break;
        }
        // 构建前缀部分
        int prefix_num = n - pos;
        for (int i = 1; i <= prefix_num; i++) {
            ret += '0' + i;
        }
        // 迭代构建后续的部分
        char cond[9];
        int j = 0;
        for (int i = prefix_num+1; i <= n; i++) {
            cond[j++] = '0' + i;
        }
        cond[j] = '\0';
        k--;
        for (int i = 1; i < pos; i++) {
            // prefix_num + i 位
            // 除当前原始外剩下的元素个数 pos - i
            int f = k / p[pos-i];
            ret +=  cond[f];
            // 删掉f位置的字符
            j--;
            for (int x = f; x < j ; x++) { cond[x] = cond[x+1];} cond[j] = '\0';
            // 剩下的序排位个数
            k %= p[pos-i];
        }
        ret += cond[0];
        return ret;
    }
private:
    int p[10];
};

knzeus
72 声望28 粉丝

行万里路,读万卷书