每天一道LeetCode-----找到第k个排列
来源:互联网 发布:山师教务处网络教育 编辑:程序博客网 时间:2024/09/21 06:35
Permutation Sequence
原题链接Permutation Sequence
给定n和k,求[1,2,3,...,n]
这个序列的全排列中第k个排列
可以调用k次next_permutation
获取结果,但是next_permutation
内部实现比较慢。
首先考虑能不能确定第k个排列是以哪个数字开头的呢,以[1,2,3,4]
的全排列为例,找第14个排列
- 以1开头的排列总共有3!个,原因是第一个位置是1,剩下3个位置可以随便排列,有6个
- 以2开头的排列总共有3!个,原因是第一个位置是2,剩下3个位置可以随便排列,有6个
- 此时已经有12个排列
- 所以剩下的两个排列即第14个排列一定在以3开头的排列中
用这种方式继续缩减数量,以3开头的排列中最小的为[3,1,2,4]
,3已经固定,那么就找[1,2,4]
的全排列的第2个排列,就是整个排列的第14个排列
- 以1开头的排列共有2!个,原因是第二个位置是1,剩下2个位置可以随便排列,有2个
- 此时已经有两个排列,可以确定结果一定在以
[3,1]
开头的排列中,即[3,1,2,4]
或[3,1,4,2]
继续缩减数量,以[3,1]
开头的排列中最下的为[3,1,2,4]
,[3,1]
已经固定,那么就找[2,4]的全排列的第2个排列,就是[1,2,4]的全排列的第2个排列,也就是整个排列的第14个排列
- 以2开头的排列共有1!个,原因是第三个位置是2,剩下一个位置给4,有1个
- 以4开头的排列共有1!个,原因是第三个位置是4,剩下一个位置给12,有1个
- 此时已经有两个排列,可以确定结果是以4开头的排列,即
[4,2]
,所以结果为[3,1,4,2]
所以,可以每次确定一个大范围,在大范围的基础上进一步缩小范围,直到最后只有一个数字为止。遍历n遍即可。
假设某次需要找到第k个排列(k从1开始),以第i个位置开头(i从1开始),上述过程可以表示为
要找的排列的开头是所剩数字中的第k / (n-i)!个 (整除)或第k / (n-i)! + 1个(非整除)数字,(从1开始)
原因
上述第一步,序列为[1,2,3,4],k为14,i为1,(n-i)!为6,k / (n-i)!为2,此时因为要找第14个排列(从1开始),以1,2开头的各占6个,所以在以3开头的排列中找,所以应该是k / (n-i)! + 1(非整除),即第3个数字,从1开始,为3
上述第二步,序列为[1,2,3],确定以3开头后,k为2,i为2,(n-i)!为2,k / (n-i)!为1,此时因为要找第2个排列,以1开头的就有2个,所以在以1开头的排列中找,所以应该是k / (n-i)! (整除),即第1个数字,从1开始,为1
上面需要根据情况讨论的原因是位置索引都是从1开始的,如果索引从0开始,那么就不会有这么多问题,此时k为14,即要找第13个排列(从0开始)
上述第一步,序列为[1,2,3,4],k为13,i为1,(n-i)!为6,k / (n-i)!为2,k / (n-i)!为2,即第2个数字(从0开始),为3
上述第二步,序列为[1,2,3],确定以3开头后,k为1,i为2,(n-i)!为2,k / (n-i)!为0,即第0个数字,为1
代码如下
class Solution {public: string getPermutation(int n, int k) { vector<int> factorial(n+1, 1); for(int i = 2; i <=n; ++i) factorial[i] = i * factorial[i - 1]; vector<int> nums; for(int i = 1; i <= n; ++i) nums.emplace_back(i); string res(""); for(int i = 1; i <= n; ++i) { /* 找开始点 */ int index = k / factorial[n - i]; /* 如果非整除,加一 */ if(k % factorial[n - i] != 0) ++index; res += (nums[index - 1] + '0'); nums.erase(nums.begin() + index - 1); k = k - ((index - 1) * factorial[n - i]); } return res; }};
- 每天一道LeetCode-----找到第k个排列
- LeetCode | Permutation Sequence(找到全排列中的第k个排列)
- 每天一道LeetCode-----将链表每k个节点逆序一次
- [LeetCode] k-th permutation 第k个排列
- 第k个排列
- 每天一道LeetCode-----找到1,2,...,n这n个数所有的组合,每个组合有k个元素,且元素大小递增
- 每天一道算法题(14)——N个降序数组,找到最大的K个数
- Permutation Sequence 求第k个的排列序列 @LeetCode
- leetcode 60. Permutation Sequence 第K个全排列
- 每天一道LeetCode-----两个有序数组合并后的第K个数
- 第k个排列数
- LintCode-第k个排列
- LinkCode 第k个排列
- 第k个排列-LintCode
- 每天一道算法题7 查找链表中倒数第k个结点
- 每天一道算法题——链表中倒数第k个结点
- 每天一道LeetCode-----将数组/链表后k个元素移动到前面
- 在升序排列的2个数组中找到第K大的数值
- Ajax技术实战操练课堂学习笔记
- 模式识别-高维空间降维的重要性
- 程序员的九大不幸
- 程序员写在猝死的前一天
- 【知识发现】天池平台新浪微博互动预测-ItemCF推荐方法
- 每天一道LeetCode-----找到第k个排列
- 将java工程打包成jar包
- idea .java文件右下角有个红色j的解决方法
- SAP 项目实施流程
- 【个人笔记】onsubmit
- Java之父:C语言是撑起一切的基石
- InterlliJ Debug方式启动:Method breakpoints may dramatically slow down debugging
- 反编译
- IT创业者需要知道的八个神奇定律