题目描述
给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列。
按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:
“123”
“132”
“213”
“231”
“312”
“321”
给定 n 和 k,返回第 k 个排列。
示例
输入:n = 3, k = 3
输出:“213”
限制
1 <= n <= 9
1 <= k <= n!
题解
方法1:暴力
比较常规的回溯递归(用时6524ms),很明显不是这道题的本意,非常不推荐
class Solution:
def getPermutation(self, n: int, k: int) -> str:
l = [i for i in range(1, n + 1)]
self.cnt = 0
def dfs(l, ans, k):
if 0 == len(l):
self.cnt += 1
return self.cnt == k
for i in range(len(l)):
tmp = l.pop(i)
ans.append(tmp)
if dfs(l, ans, k):
return True
ans.pop()
l.insert(i, tmp)
return False
ans = []
dfs(l, ans, k)
return ''.join([str(i) for i in ans])
方法2:数学
(用时28ms)
根据题目中的数字排列的顺序,我们可以依次确定最终答案中的每一位的值。
以getPermutation(5, 47) = "25413"为例:
第一位的确定:1,2,3,4,5的全排列最终得到的答案顺序时这样的:1xxxx,2xxxx,3xxxx,4xxxx,5xxxx,每一种都有4!=24种可能,此处的k=47=24+23,相当于1xxxx对应的排列数完了,2xxxx对应的排列数到了第23个,所以可以确定首位数字是2。下一次我们要对1,3,4,5进行全排列,选出其中第23个序列,此处相当于更新了k=23。
第二位的确定:同理,由于3!=6,23=6+6+6+5,所以第二位数字是5,更新k=5,候选数字变为1,3,4。
第三位的确定:2!=2,5=2+2+1,所以第三位数字是4,更新k=1,候选数字变为1,3。
第四位的确定:1!=1,1=1,所以第4位数字是1,此时k不能更新为0,要更新为1。
第五位就是最后一个数字3了。
class Solution:
def getPermutation(self, n: int, k: int) -> str:
mem = [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362800]
l = [i for i in range(1, n + 1)]
ans = ""
for i in range(n, 0, -1):
ans += str(l.pop((k - 1) // mem[i - 1])) #此处不写k//mem[i-1]是保证当k整除mem[i-1]时取k//mem[i-1]-1的值
k = (k - 1) % mem[i - 1] + 1 #此处不直接写k%=mem[i-1]让k-1是保证当k整除mem[i-1]时得到的不是0而是mem[i-1]
return ans