一. Permutation Sequence
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 (ie, 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.
Difficulty:Medium
TIME:TIMEOUT
解法
这道题其实很有意思,之前做过Next Permutation,我也尝试用那种方法解这道题,结果会超时,而且并没有找到一种有序的递归解法(深度优先搜索在 9! 的时间复杂度下应该不会超时)。
不过,这道题既然是求第k个排列,那么我们其实毫不关心前面的k-1个排列究竟是怎样的
- 如果给定序列<1,2,3>,那么可以把<1,2,3>的排列分解为三种子排列分别为<1,x,x>,<2,x,x>,<3,x,x>,其中x为剩下的两个数字中的一个。我们知道每个子排列的排列总数为 2!=2 ,因此子排列的序号范围便为1~2,3~4,5~6。
- 然后,开始考虑序号和第一个数字之间的关联,如果都减一变为0~1,2~3,4~5(这里减一是正确的,加一反而不能处理很多情况),然后除以2,那么就为0,1,2,都加一变成1,2,3,这个数字就是第一个数字(这里的1,2,3并不是指1,2,3数字本身,而是指第1,2,3大的数字)。
- 既然找到了第一个数字,那么我们减去第一个数字带来的影响,那么就可以开始考虑剩下的数字了,这个时候又回到了最开始的处理方法。
比如以<1,2,3>为例,我们要找第四个排列,步骤如下:
- (4−1)/2=1 ,然后 1+1=2 ,第一个数字就是第二大的数子,这里为2,接着减去第一个数字带来的影响, 4−2∗1=2
- (2−1)/1=1 ,然后 1+1=2 ,第二个数字也是第二大的数字,这里为3,接着减去第二个数字带来的影响, 2−1∗1=1
- ….
- 最后结果为<2,3,1>
string getPermutation(int n, int k) {
string s;
vector<int> v(n + 1, 1);
vector<char> ch(n, '0');
for(int i = 1; i <= n; i++) {
v[i] = i * v[i - 1];
ch[i - 1] += i;
}
while(n) {
int num = (k - 1) / v[n - 1]; //这里判断需要第几大的数字
k -= v[n - 1] * num; //减去这个数字带来的影响
s.push_back(ch[num]);
ch.erase(ch.begin() + num); //删掉该数字
n--;
}
return s;
}
代码的时间复杂度为 O(n2) 。