【leetcode】60. Permutation Sequence 全排列的第k位序的排列形式

knzeus發表於2019-05-11

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] = ` `;
        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] = ` `;
            // 剩下的序排位個數
            k %= p[pos-i];
        }
        ret += cond[0];
        return ret;
    }
private:
    int p[10];
};

相關文章