天天刷leetcode——60. 第k个排列

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 (n1)=2
2 + (permutations of 1, 3):一共 ( n − 1 ) ! = 2 (n-1)!= 2 (n1)=2
3 + (permutations of 1, 2):一共 ( n − 1 ) ! = 2 (n-1)!= 2 (n1)=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=51 (减去1是因为程序中索引从0开始), k / ( n − 1 ) ! = 4 / ( 3 − 1 ) ! = 2 k/(n-1) != 4/(3-1)! = 2 k/(n1)!=4/(31)!=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%(n1)!=4%(31)=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/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值