60. Permutation Sequence 第 K 个字典序排列

60. Permutation Sequence 第 K 个字典序排列

解法一:枚举 K-1 次

代码量极短,好想但是比较耗时 时间复杂度:O(n!) 空间复杂度:O(n)

string getPermutation(int n, int k) {
    string a(n, '0');
    for(int i=1;i<=n;++i) a[i-1]+=i;
    if (n == 1 || k == 1) return a;
    for(int i=0;i<k-1;i++) next_permutation(a.begin(), a.end());
    return a;
}

解法二:找到字典序选取的规律与K的关系

证明:K / (n-1)! 为选择的下标,余数可用于下一次选择,直到 n 个数被选完 例如:1, 2, 3, 4。n = 4 第一个数字为 1,有 (n-1)! 种排列方式 第一个数字为 2,也有 (n-1)! 种排列方式 因此商即为 [1, 2, 3, 4] 的下标,余数表示在此位数字固定后的下一位的字典序列的位置,递归和非递归的解法都可以

时间复杂度:O(n) 空间复杂度:O(n)

string getPermutation(int n, int k) {
    string a(n, '0');
    int i;
    for(i=1;i<=n;++i) a[i-1]+=i;
    if (n == 1 || k == 1) return a;

	// 阶乘的记忆数组
    vector<int> v(n, 1);
    for(i=n-3;i>=0;--i) v[i] = v[i+1]*(n-1-i);

    k--;
    string res(n, '0');
    for(i=0;i<n;++i) {
        int select = k/v[i];
        k %= v[i];
        res[i] = a[select];
		// 选了一位字符后要从候选字符中去除
        a.erase(select, 1);
    }
    return res;
}

收获

  1. 通过寻找 k 与 字典序排列顺序的规律和构建阶乘表大大地减少了计算量
  2. stl 的 erase 是一个 O(n) 的操作

#排列组合