数学基础:康托展开
对于具有n个元素的集合,以’1’开头的数字序号范围是[1,(n-1)!],以’2’开头的数字序号范围是[(n-1)!,2(n-1)!]…以此类推。
所以寻找n个数中的第k个排列,就可以运用上述方法:确定n个数中第一个数,再去掉该数,运用同样方式确定(n-1)个数中的第一个数。
例:求 n=5 , k = 17
k = 17,前边有16个排列,即寻找前面有16个排列的排列。
{1,2,3,4,5}
16 ÷ 4!= 0 … 16 五位数中第一位的序号范围在[1,4!],所以第一位是’1’。
{2,3,4,5}
16 ÷ 3!= 2 … 4 五位数中第二位的序号范围在[23!+1,33!],所以第二位是’4’。
{2,3,5}
4 ÷ 2!= 2 … 0 五位数中第三位的序号范围在[22!+1,32!],所以第三位是’5’
{2,3}
0 ÷ 1!= 0 … 0 第四位是’2’
{3}
0 ÷ 0!= 0 … 0 第五位是‘3’
所以n = 5,k = 17 的数为"14523"
时间复杂度:O(k*n)(阶乘时间复杂度为n,执行k次)
C++代码:
class Solution{
int factorial(int n)
{
int result = 1;
for (int i = 1; i <= n; i++)
result *= i;
return result;
}
public:
string getPermutation(int n, int k) {
vector<int> num_set;
for (int i = 1; i < n + 1; i++)
num_set.push_back(i);
string result;
k--;
for (int i = n - 1; i > 0; i--)
{
int permute = k / factorial(i);
k %= factorial(i);
result.push_back(num_set[permute] + '0');
num_set.erase(num_set.begin() + permute);
}
result.push_back(num_set[0] + '0');
return result;
}
};