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;
}收获
- 通过寻找 k 与 字典序排列顺序的规律和构建阶乘表大大地减少了计算量
- stl 的 erase 是一个 O(n) 的操作
#排列组合