LCP:60 排列序列
给出集合 [1,2,3,...,n]
,其所有元素共有 n!
种排列。
按大小顺序列出所有排列情况,并一一标记,当 n = 3
时, 所有排列如下:
"123"
"132"
"213"
"231"
"312"
"321"
给定 n
和 k
,返回第 k
个排列。
示例 1:
输入:n = 3, k = 3
输出:"213"
示例 2:
输入:n = 4, k = 9
输出:"2314"
示例 3:
输入:n = 3, k = 1
输出:"123"
最近电脑坏了,去修理好久,所以最近没更leetcode啊,我的绿屏计划都没了🥲
关于0基数和1基数的思考
计算机中常常从0开始计数,而我们在表述中往往从1开始计数,对于问题的转换,我们推荐从问题的一开始就统一基数,如果不统一会给后面的代码带来不必要的麻烦。
比如这个问题,K=9是什么基数,显然来看,是1基数。我们在处理的时候,就要先一步来把K=9转化为0基数的K=8,因为后面我们基于数组的算法就是0基数,不在开头统一绝对让人迷惑。相信你也看出来了
(0基数计数)=(1基数计数)-1;
解题思考
-
从上到下的排列,同一个开头的数字有几个?当然是余下的N-1个数字的全排列了,(N-1)!个嘛
-
所以第K(1)的开头在哪里?那就是求K-1(0)的开头在哪里? 显然
对于
vector<char> vecc = { '1','2','3','4','5','6','7','8','9' };
b e g i n n u m = v e c c [ k ( n − 1 ) ! ] beginnum=vecc[\frac{k}{(n-1)!}] beginnum=vecc[(n−1)!k]
-
下一步,每个数字只会出现一次,故出现完就要移除
-
下一步是递归,算出来第一个数字,那接下来确定第二个数字,n变为n-1,k变为k%(n-1)! ,参与递归即可
-
上面的索引是对次序而言的,如果第一位是3,那余下的数字是1246789,若算出k/(n-1)!=3,那实际上的数字是5(这点比较关键读者可以思考一下)
-
代码
class Solution {
public:
vector<int> tannum = { 1,1,2,6,24,120,720,5040,40320,362880 };
vector<char> vecc = { '1','2','3','4','5','6','7','8','9' };
//记得把ans设为对象内变量,这也递归调用的都是这个
string ans;
void getPermutation_T(int n, int k)
{
if (n == 0) return;
int tnum = k / tannum[n - 1];
ans += vecc[tnum];
//每个数字只会出现一次,故排上之后就应该删除
vecc.erase(vecc.begin() + tnum);
getPermutation_T(n - 1, k % tannum[n - 1]);
}
string getPermutation(int n, int k) {
//预处理
getPermutation_T(n, k - 1);
return ans;
}
};