60第K个排列

题目:给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列。按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:
    "123"
    "132"
    "213"
    "231"
    "312"
    "321"
给定 n 和 k,返回第 k 个排列。
说明:给定 n 的范围是 [1, 9]。给定 k 的范围是[1,  n!]。

来源: https://leetcode-cn.com/problems/permutation-sequence/

法一:自己的代码    耗时很短,利用python自带的阶乘函数计算耗时会更短

思路:转化为一个纯数学的问题,关键是要把每种情况都考虑到,特别是除n!后是整数的情况,举例的时候就要把每种情况都枚举到,编程才不会出错

import math
class Solution:
    def getPermutation(self, n: int, k: int):
        # 自定义阶乘函数
        def n_factorial(x):
            if x == 0:
                return 1
            else:
                return x * n_factorial(x-1)
        nums = [i+1 for i in range(n)]
        result = ''
        while n > 0:
            n = n - 1
            # 通过观察数据可以看出,假如输入是(4,9),则说明以1开头的有3!个,以2开头的有3!个,
            # 所以用9除以3的阶乘是1.5,1,5向上取整为2,即nums中的第二个数2是结果中的第一个数,
            # 再用9减去6为3表示从2开始的组别中找第三个数,
            res = k / n_factorial(n)
            res_up = math.ceil(res)
            # 注意这里向下取整必须是向上取整后减1,这是因为比如输入的是(4,6),则6除3!为1,1-1=0,所以不可直接向下取整
            res_down = res_up - 1
            k = k - res_down * n_factorial(n)
            result = result + str(nums[res_up-1])
            del nums[res_up-1]
            print('-'* 20)
            print('k', k)
            # print(res)
            print(res_up)
            # print(res_down)
        return result
if __name__ == "__main__":
    duixiang = Solution()
    a = duixiang.getPermutation(4,9)
    print(a)
View Code

法二:自己的代码    利用回溯,但是超时,超时是因为没有用continue,每个分支都要检查一遍

class Solution:
    def getPermutation(self, n: int, k: int):
        nums = [i+1 for i in range(n)]
        global count,result
        count = 0
        def backtrack(a='', nums=nums, ):
            global count,result
            # print('k',count)
            if count == k:
                return
            if len(a) == n:
                count += 1
                # print('count', count)
                if count == k:
                    result = a
                    # exit()
                # return count
            for i,j in enumerate(nums):
                r = nums.copy()
                del r[i]
                # print('ttt',count)
                # sign,result = backtrack(a+str(j), r)
                backtrack(a+str(j), r)
        backtrack()
        return result
View Code

改进后的不会超时,注意这里return的用法,非常巧妙

class Solution:
    def getPermutation(self, n: int, k: int):
        nums = [i+1 for i in range(n)]
        from1to9_factorial = [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880]
        def backtrack(a='', nums=nums,k = k ):
            # 一旦满足条件立即逐层返回a,结束所有函数
            if len(a) == n:
                return a
            t = from1to9_factorial[len(nums) - 1]
            for i,j in enumerate(nums):
                if k > t:
                    # 执行剪枝操作,如果大于t了,就结束本次循环
                    k = k - t
                    continue
                # r中是下次for循环要遍历的数
                r = nums.copy()
                del r[i]
                # 这里必须用return,避免了定义全局变量来解决问题
                return backtrack(a+str(j), r, k)
        return backtrack()
if __name__ == "__main__":
    duixiang = Solution()
    a = duixiang.getPermutation(4,10)
    print(a)
View Code

 

 

 

 

 

posted on 2019-11-28 14:38  吃我一枪  阅读(148)  评论(0编辑  收藏  举报

导航