题目描述(Medium)
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 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.
Given k will be between 1 and n! inclusive.
题目链接
https://leetcode.com/problems/permutation-sequence/description/
Example 1:
Input: n = 3, k = 3
Output: "213"
Example 2:
Input: n = 4, k = 9
Output: "2314"
算法分析
康托展开是一个全排列到一个自然数的双射,因此是可逆的。对于康托展开,对(1,2,3,4,5)可以算出第62个排列组合为34152。由上述的计算过程可以容易的逆推回来,具体过程如下:
用 61 / 4 != 2余13,说明比首位小的数有2个,所以首位为3。
用 13 / 3 != 2余1,说明在第二位之后小于第二位的数有2个,所以第二位为4。
用 1 / 2 != 0余1,说明在第三位之后没有小于第三位的数,所以第三位为1。
用 1 / 1 != 1余0,说明在第二位之后小于第四位的数有1个,所以第四位为5。
最后一位自然就是剩下的数2。
通过以上分析,所求排列组合为 34152。
提交代码:
class Solution {
public:
string getPermutation(int n, int k) {
string S(n, '0');
string result;
int base = 1;
for (int i = 1; i < n; ++i)
base *= i;
for (int i = 0; i < n; ++i)
S[i] += i + 1;
--k;
for (int i = n - 1; i > 0; --i)
{
auto iter = next(S.begin(), k / base);
result.push_back(*iter);
S.erase(iter);
k %= base;
base /= i;
}
result.push_back(S[0]);
return result;
}
};
测试代码:
// ====================测试代码====================
void Test(const char* testName, int n, int k, string expected)
{
if (testName != nullptr)
printf("%s begins: \n", testName);
Solution s;
string result = s.getPermutation(n, k);
if (result == expected)
printf("passed\n");
else
printf("failed\n");
}
int main(int argc, char* argv[])
{
Test("Test1", 3, 3, "213");
Test("Test2", 4, 9, "2314");
return 0;
}