更多精彩内容,请关注【力扣中等题】。
题目
难度:★★★★☆
类型:数组
方法:递归、数学
原题链接
给出集合 [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"
示例 1
输入: n = 4, k = 9
输出: "2314"
解答
关于如何通过回溯法或递归法实现全排列可移步全排列。
我们观察这样一个现象,对于从1到n的数组,其全排列有n!个可能性,这些组合是如何排列的呢?
我们思考这样一个问题,一天有246060=86400秒,但是如果让你计算第16589秒是几时几分几秒,你会如何计算呢?
正常情况下我们会首先计算几点,看看这个时刻落在24小时或24个片段中的哪一个,通过将时刻除以3600秒我们获得了4余2189秒,说明是4点,我们继续查看是几分,通过把余数2189除以60秒,我们获得了36余29,那么我们就很清楚的得到了最后的时间:4时36分29秒。
这个问题与之类似。我们列出来[1, 2, 3, 4]的全排列,寻找第9个全排列:
1234
1243
1324
1342
1423
1432
2134
2143
2314
2341
2413
2431
3124
3142
3214
3241
3412
3421
4123
4132
4213
4231
4312
4321
观察发现,总共有4×3×2×1个可能,按照第一个元素可以分为四段,分别以1,2,3和4开头,且以1开头的情况下又有3×2个可能,又可以分为3段,分别以剩余三个数字开头……因此,我们可以首先用9除以6取整来判断第9个排列在第几段,得知落在了第二段,因此第一个元素是2。余数3可以用于后续元素的判断,这时还没有使用的元素是1,3和4,用余数3除以子段的个数2可以得到1余1,那么第二个元素就是3,这时前两个元素“23”就确定下来了,同样的方法,一直计算下去,就可以获得每一位的数值。
在编码过程中需要注意的是,我们用于计算商和余数所用的除数是一个阶乘,这个阶乘的计算与输入和当前情况有关,需要准确计算。
import math
class Solution:
def getPermutation(self, n: int, k: int) -> str:
visited = [0 for _ in range(n)] # e.g. [0, 0, 0]
fact = [math.factorial(n-i-1) for i in range(n)] # e.g. [2!, 1!, 0!]
ans = ''
k -= 1
for i in range(n):
t = k / fact[i]
for j in range(n):
if not visited[j]:
if t == 0:
break
t -= 1
ans += str(j+1)
k %= fact[i]
visited[j] = 1
return ans
如有疑问或建议,欢迎评论区留言~