LeetCode/60. 第k个排列
60. 第k个排列
给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列。
按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:
"123""132""213""231""312""321"
给定 n 和 k,返回第 k 个排列。
说明:
- 给定 n 的范围是 [1, 9]。
- 给定 k 的范围是[1, n!]。
示例1:
1 | 输入: n = 3, k = 3 |
示例2:
1 | 输入: n = 4, k = 9 |
来源:力扣(LeetCode)
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解:
本题一看到排列,我们就想到了回溯。如果单纯的生成所有可能取值,再从中获取目标字符串肯定会超时。通过观察,我们可以发现一定的规律,即数字的全排列是成组的。
1 | 举个例子,比如我们的n = 4, k = 9,我们有如下的排列: |
有了如上的规律,那么我们就可以缩减问题的规模,通过n和k可以算出目标字符串是以哪个数字开头的,然后通过剩下的数字进行排列,再定位我们要找的是该组中的第几个,就可以得到最终的结果。比如说,我们现在的n = 4, k = 9,我们可以计算出每组有(n-1)!=3!=6个排列,然后我们给positon + gap和k进行比较,同时初始化一个变量count用来算出第一个数字是多少,如果positon + gap小于k,说明我们要找的目标字符串肯定不在该组中,如果positon + gap大于k,则该组中有我们的目标字符串。我们通过position = k - (position - gap) - 1来定位目标字符串在该组的位置,通过count--来定位目标字符串在哪个组中。最后,我们用backtrack来生成剩下数字的排列,进行拼接就可以获取到目标字符串。
具体代码如下:
1 | class Solution { |
当然了,还有一种数学归纳的方法,可以直接判断出目标字符串。所用到的原理和我们上述的比较positon + gap和k的大小,来判断当前位置该填写哪个数字。我们还是以上述的n = 4, k = 9举例,计算出每组有(n-1)!=3!=6个排列,可以定位到第一个位置的数字为2,利用(n-2)!=2!=2和k = k - m * (n - 1)!= 3 ,这里的m是指经过多少个gap定位到目标字符串。接着我们继续重复上面的过程继续往下搜索,由于2 < 3,所以我们可以确定第二位数组为3,利用(n-3)!=1!=1和k = k - m * (n - 2)!= 1,最终可以定位到2314,即我们需要找的目标字符串。
上述两种方法,都对排列的顺序有要求,如果顺序打乱,就不能得到想要的结果。
具体代码请参考官网题解

