60. 第k个排列
题目描述
给定 n 和 k,返回第 k 个排列。
解题思路
1. 直接回溯算法DFS
求出所有的排列,然后确定k个
def getPermutation(self, n: int, k: int) -> str:
nums = [str(i+1) for i in range(n)]
def back(nums,track):
if len(track) == len(nums):
tmp = ''.join(track)
res.append(tmp)
return
for i in range(len(nums)):
if nums[i] in track:
continue
track.append(nums[i])
back(nums,track)
track.pop()
track = []
res = []
back(nums,track)
return res[k-1]
时间复杂度太高了!
2. 数学方法
主要思想:挨个求每层的数字是什么。假设n = 3,其排列组合的顺序如下:
1 + (permutations of 2, 3) :一共
(
n
−
1
)
!
=
2
(n-1)!= 2
(n−1)!=2 个
2 + (permutations of 1, 3):一共
(
n
−
1
)
!
=
2
(n-1)!= 2
(n−1)!=2 个
3 + (permutations of 1, 2):一共
(
n
−
1
)
!
=
2
(n-1)!= 2
(n−1)!=2 个
n
n
n个数字的排列数为
n
!
n!
n!, 3个数的排列数为6。假如
k
=
5
k=5
k=5,那么落在第3个排列的位置:
2 + (permutations of 1, 3)。
令
k
=
5
−
1
k=5-1
k=5−1 (减去1是因为程序中索引从0开始),
k
/
(
n
−
1
)
!
=
4
/
(
3
−
1
)
!
=
2
k/(n-1) != 4/(3-1)! = 2
k/(n−1)!=4/(3−1)!=2, 在数列[1, 2, 3]中索引为2的数字为3,所以第一个数字为3。
该问题就变成了求
[
1
,
2
]
[1,2]
[1,2]的全排列,求第
k
=
k
%
(
n
−
1
)
!
=
4
%
(
3
−
1
)
=
2
k= k\%(n-1)!=4\% (3-1)= 2
k=k%(n−1)!=4%(3−1)=2的排列顺序。
同理求得数字…
知道所求的全排列长度为1,停止递归。
def getPermutation(self, n: int, k: int) -> str:
def fac(n):
mul = 1
for i in range(1,n+1):
mul *= i
return mul
tokens = [str(i) for i in range(1, n+1)]
res = ''
k = k-1
while n > 0:
n -= 1
a, k = divmod(k, fac(n))
res += tokens.pop(a)
return res
3. 回溯+剪枝
def per(k,n):
n_ = [1]
# n_表示i个数字能组成全排列的个数为多少
for i in range(1, n):
n_.append((i + 1) * n_[-1])
nums = list(range(1, n + 1))
track = []
def back(k):
if not nums:
return
# 去掉一个数字,剩余的数字可以组成多少种可能
cnt = n_[len(nums) - 2]
print(cnt)
for i in range(len(nums)):
# 剪枝,如果k大于cnt,大于能组成数字的全排列个数
if k > cnt:
k -= cnt
continue
else:
track.append(str(nums[i]))
nums.pop(i)
back(k)
return
back(k)
return ''.join(track)
reference
[1] leetcode 60. 第k个排列: https://leetcode-cn.com/problems/permutation-sequence/submissions/