(1条消息) 字节尿性,康托展开求第K个排列!
今天是小浩算法 “365刷题计划” 第 109 天。继续为大家讲解 leetcode 第 60 题,是一道中等难度的题目。
排列类别的问题主要就两个,一个是全排列:
另一个就是本题(两个题在剑指offer都出现了):
进刷题群的小伙伴
关注回复【进群】即可
01
PART
第K个排列
题目比较绕,耐心点还是可以看懂的~加油!
题目:给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列。
按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:
"123"
"132"
"213"
"231"
"312"
"321"
给定 n 和 k,返回第 k 个排列。
说明:
给定 n 的范围是 [1, 9]。
给定 k 的范围是[1, n!]。
给出两个示例:
示例 1:
输入: n = 3, k = 3 输出: "213"
示例 2:
输入: n = 4, k = 9 输出: "2314"
02
PART
题解分析
这道题目的标签标的数学和回溯算法,所以我们分别用数学和回溯的方法来解题。
从数学方法说起,先讲一下康托展开。
那康托展开是干嘛的?用来计算当前排列在所有由小到大全排列中的顺序。卧槽,不就是本题吗。
听不懂?就是说如果你知道 1234 是序号 1,1243 是 序号2,这个公式就可以直接告诉你 4132 的序号是多少!
公式是这样的:
解释一哈:
这个 X 就是最终的序号值,比实际序号少一位,因为可以看到康托展开第一位计算的值是 0 。
网上看到的很多图可能名次是从 1 开始,这个大家注意一下就行:
关键是这个
,这个其实就是看原数的第 i 位在当前未出现的元素中是排在第几个。
感觉这句话有点拗口,用上面出现的问题解释一下:1234 是序号 1,1243 是 序号 2, 4132 的序号是多少?
解释:第一个数是 4,比 4 小的并且还没有出现过的数有 3 个(123),第二个数是 1,比 1 小的并且还没有出现过的数为 0 个。第三个数是 3,比 3 小的并且还没有出现过的数为 1。第四个数是 2 ,比 2 小的并且还没有出现过的数为 0 个。
有 X = 3*3!+ 0*2!+ 1*1!+ 0*0!= 19,此时的序号为 19+1 = 20。还不明白的看下下面这个图:
然后我们把上面的东西反着来,就叫做 逆康托展开。换句话说,就是给我们了 X 的值,让我们求
。
对于 逆康托展开,我还是给一个例子。比如 nums 还是 1234,我们要找第 15 位。那么要进行以下几步:
首先,因为 X 比实际序号少一位,所以我们要用实际序号减1,也就是 15 - 1 = 14。
目标值的第一个字符,14 / 3! = 2 ... 2 (商2余2),没有已使用的字符,第一个字符取在未使用的字符中排增序第3。即3
目标值的第二个字符,2 / 2! = 1 ... 0,已使用的字符为3,第二个字符取在未使用的字符中增序排第2。即2
目标值的第三个字符,0 / 1! = 0 ... 0,已使用的字符为2和3,第三个字符取在未使用的字符中增序排第1。即1
目标值的第三个字符,0 / 0! = 0 ... 0,已使用的字符为1,2和3,第四个字符取在未使用的字符中增序排第1。即4
那么要求的这个序列为:3214。
可以查下上面的表,发现是正确的。如果看不懂,可以回到上面的例子再看看,其实就是把上面过程倒着来。
最后,我们再将逆康托展开进行应用:
//JAVAclass Solution { public String getPermutation(int n, int k) { StringBuilder sb = new StringBuilder(); // 候选数字 List<Integer> candidates = new ArrayList<>(); // 分母的阶乘数 int[] factorials = new int[n+1]; factorials[0] = 1; int fact = 1; for(int i = 1; i <= n; ++i) { candidates.add(i); fact *= i; factorials[i] = fact; } //预处理 k -= 1; for(int i = n-1; i >= 0; --i) { // 计算候选数字的index int index = k / factorials[i]; sb.append(candidates.remove(index)); k -= index*factorials[i]; } return sb.toString(); }}
03
PART
相似题目
说是相似题目,但是其实下面两个题目我都是用回溯来求解的啦。算是通用解法吧~大家有兴趣也可以用回溯来解下本题。
我把我写的所有题解都整理成了一本电子书,每道题都配有完整图解。关注回复【999】就可以下载了。