分类:algorithm| 发布时间:2017-03-12 22:23:00
给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列。
按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:
给定 n 和 k,返回第 k 个排列。
说明:
示例 1:
输入: n = 3, k = 3
输出: "213"
示例 2:
输入: n = 4, k = 9
输出: "2314"
最简单的方法就是调用 k 次 31. 下一个排列 这一题解出的函数。
class Solution {
public:
string getPermutation(int n, int k) {
string ret;
for (int i = 0; i < n; ++i)
ret += '1' + i;
while (--k) nextPermutation(ret);
return ret;
}
void nextPermutation(string& nums) {
if (nums.empty()) return;
// in reverse order, find the first number which is in increasing trend (we call it violated number here)
int i;
for (i = nums.size() - 2; i >= 0; --i) {
if (nums[i] < nums[i+1]) break;
}
// reverse all the numbers after violated number
reverse(begin(nums)+i+1, end(nums));
// if violated number not found, because we have reversed the whole array, then we are done!
if (i == -1) return;
// else binary search find the first number larger than the violated number
auto itr = upper_bound(begin(nums)+i+1, end(nums), nums[i]);
// swap them, done!
swap(nums[i], *itr);
}
};
当然这种方法效率极差,并不是最好的方法。
通过观察序列可知,假设序列的长度为 n,从左往右数第 i 个数字需要与 i + k / (n - i - 1)! 个数字进行交换(在 i..n 序列为最小序列的情况下)。 因此可以得出如下解法:
class Solution {
public:
string getPermutation(int n, int k) {
string ret;
for (int i = 0; i < n; ++i)
ret.push_back('1' + i);
// generate weight array
vector<int> weights(n, 0);
for (int i = 1, weight = 1; i < n; ++i, weight = weight * i) {
weights[n - i - 1] = weight;
}
--k;
for (int i = 0; i < n - 1; ++i) {
int j = k / weights[i];
if (!j) continue;
k -= (j * weights[i]);
j = i + j;
char tmp = ret[j];
// sort nums[i + 1...n] to the minimal
for (int ii = j - 1; ii >= i; --ii)
ret[ii + 1] = ret[ii];
ret[i] = tmp;
}
return ret;
}
};