题目:
给出集合 [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”
思路:
假设n为4,我们要求第14个排列,k=14。
- 首先,确定第一位的数字,候选1,2,3,4
以1开头的排列有3!=6
个(1固定,234全排列),而我们要求第14个排列,所以不是1开头。
以2开头的排列也有6个,加上以1开头的一共12个,仍然小于14,所以也不是以2开头
以3开头的排列也有6个,加上前面的12个一共18,大于k=14
,因此第14个排列就是以3开头。
此时,确定了第一位是3,以3开头的排列之前的排列有6*2=12个,k需要减去12以便确定后面的数字。更新后,k=2。 - 接着确定第二位数字,候选1,2,4
31开头的排列有2!=2
个,大于等于k=2
,因此第2位数字就是1。
此时k需要减去第2位是1的之前的排列,由于1是最小的,那就减去0,k仍为2。
以此类推,直到确定全部数字。
总结一下:
如何确定当前数字是候选数字的第几个?k除(候选数字个数减一的阶乘)向上取整。
代码:
class Solution(object):
def getPermutation(self, n, k):
"""
:type n: int
:type k: int
:rtype: str
"""
res = ""
fac = []
nums = []
fac.append(1)
for i in range(1, n):
fac.append(i*fac[i-1])
if k > n*fac[n-1]:
return
for i in range(n):
nums.append(1+i)
for i in range(n):
temp = k // fac[n-i-1]
# 向上取整
if k % fac[n-i-1] != 0:
temp += 1
res += str(nums[temp-1])
# 更新候选数组
nums.pop(temp-1)
k -= (temp - 1) * fac[n-i-1]
return res