LeetCode060-第k个排列

给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列。

按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:

  1. "123"
  2. "132"
  3. "213"
  4. "231"
  5. "312"
  6. "321"

给定 n 和 k,返回第 k 个排列。

说明:

  • 给定 n 的范围是 [1, 9]。
  • 给定 的范围是[1,  n!]。

示例 1:

输入: n = 3, k = 3
输出: "213"

示例 2:

输入: n = 4, k = 9
输出: "2314"

思路1:回溯法,跟46题一样,不过超时了,代码还是贴上吧。

class Solution(object):
    def getPermutation(self, n, k):
        nums = list(range(1,n+1))
        res = []
        def backtrack(nums ,tmp):
            if not nums:
                res.append(tmp)
                return
            for i in range(len(nums)):
                backtrack(nums[:i] + nums[ i +1:], tmp + [str(nums[i])])
    
        backtrack(nums ,[])

        return ''.join(res[k-1])

思路2:从一个[1,n]的区间内挑数字(也就是代码中的nums)加入答案(直到全挑光),按什么顺序挑哪个数字呢?我们需要通过数学判断。

挑选过程如下:

比如n=4,证明一共有4!种排序,那我们当前的第k个排序是什么呢?我们先确定这个排序的第一个数字。我们知道对于每个数字开头的序列,在它确定的情况下,一共有(n-1)!种情况。比如1开头的n=4的序列,一共有3!种情况。那我们就可以通过k//(n-1)!来确定这是以哪个数字开头的序列,如果等于0, 那就是1,如果等于1那就是2,以此类推。

具体来说是:

  • n 个数字有 n!种全排列,每种数字开头的全排列有 (n - 1)!种。
  • 所以用 k / (n - 1)! 就可以得到第 k 个全排列是以第几个数字开头的。
  • 用 k % (n - 1)! 就可以得到第 k 个全排列是某个数字开头的全排列中的第几个。

比如:

  1. "123"
  2. "132"
  3. "213"
  4. "231"
  5. "312"
  6. "321"

n=3,k=3

先确定开头的数字: k / (n - 1)! = 3/(3-1)!=1,那么第一个数字就是nums=[1,2,3]的索引为1的值,为2。

然后得到2+{1,3}全排列, k % (n - 1)!  = 1 ,那么指的是以2个数字开头的全排列{1,3}中的第1个,{1,3}全排列为(1,3)和(3,1),所以为(1,3),结果为213。

https://blog.csdn.net/weixin_41958153/article/details/81234523

代码实现1:

class Solution:
    def getPermutation(self, n, k):
        self.fac = [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880]
        # 找到对应的n应该对应的fac坐标,就是在第一项确定的情况一下,有(n-1)!种组合
        i = n - 1
        # 构建序列,这个num是用来储存我们当前可以添加的数的,也是为避免重复
        num = list(range(1, n + 1))
        ret = ""
        while i >= 0:
            # a用来获得我们要求的那一位在num里的下标
            a, b = k // self.fac[i], k % self.fac[i]
            # 如果刚好整除干净,证明还在上一层
            if b == 0:
                a -= 1
            if a >= 0:
                ret += str(num[a])
                del num[a]
                i -= 1
            k = b
            # 如果刚好整除完,则我们已经可以知道接下来的排序情况了,它一定是最大的
            # 所以把剩下的可选的数字reverse来制造这种效果
            if b == 0:
                for i in reversed(num):
                    ret += str(i)
                break
        return ret

s = Solution()
res = s.getPermutation(n=3,k=3)
print(res)

代码实现2:

class Solution:
    def getPermutation(self, n, k):
        series = [str(i + 1) for i in range(n)]
        res = ''
        cr = self.factorial(n)
        while n:
            cr //= n
            n -= 1
            temp = (k - 1) // cr
            res += series.pop(temp)
            k -= cr * temp
        return res

    def factorial(self, n):
        if n < 2:
            return 1
        res = 1
        for i in range(1, n + 1):
            res *= i
        return res


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值