• LeetCode 60. 第k个排列 | Python


    60. 第k个排列


    题目来源:力扣(LeetCode)
    https://leetcode-cn.com/problems/permutation-sequence

    题目


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

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

    • "123"
    • "132"
    • "213"
    • "231"
    • "312"
    • "321"

    给定 nk,返回第 k 个排列。

    说明:

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

    示例 1:

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

    示例 2:

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

    解题思路


    思路:DFS + 剪枝

    先审题,题目中说明,给定集合 [1, 2, 3, ..., n]n! 中排列。按大小顺序列出所有排列情况,进行标记,然后返回第 k 个排列。

    那么按照题意,我们最容易想到的就是列出 [1, 2, 3 ..., n] 个元素全排列,然后返回第 k 个排列,但是这样效率可能会非常低,而且我们也没有必要去求得所有的全排列。

    在这里我们可以先看看规律,题目中开始就说了,按照大小顺序列出所有排列情况。也就说,n 个元素组合的数,这个数每个元素都是从小到大进行选择的。例如示例 1:

    输入:n = 3, k = 3
    

    在这里,给定的 n 为 3,那么要组合的数为 3 位数。这里它的全排列情况如下:

    • "123"
    • "132"
    • "213"
    • "231"
    • "312"
    • "321"

    我们可以发现,第一个元素是从 1 开始选择,逐渐增大。当首元素确定之后,第二个元素同样是从小到大选择的,例如 123132

    根据上面的分析,我们可以发现,假设给定 n 个元素,

    当确定首元素时,后面元素则有 (n-1)! 中排列组合数,也就意味着首元素选择后,当前分支会产生 (n-1)! 种排列数。以此类推,当确定前面两个元素时,后面能产生的排列数则为 (n-2)!。那么:

    • 当 k 大于前面分支能够产生的排列数时,我们可以直接跳过;
    • 当 k 小于或等于当前分支产生的排列数时,也就说明要找的答案在这个分支的某个排列中,这个时候,我们递归去求解(确定逐个元素)。

    具体的代码如下。

    class Solution:
        def getPermutation(self, n: int, k: int) -> str:
            # 阶乘数组
            arr = [1 for _ in range(n+1)]
            for i in range(2, n+1):
                arr[i] = arr[i-1] * i
    
            used = [False for _ in range(n+1)]
    
    
            def dfs(k, tmp):
                """
                Args:
                    tmp: 排列元素选择数组
                """
                cnt = len(tmp)
    
                if cnt == n:
                    return ''.join(tmp)
                
                # 排列数,
                # 这里注意,刚开始排列数组中元素个数 cnt 为 0,
                # 此时要开始添加元素,所以要去除当前元素,计算后续的排列数,
                # 所以排列数为 (n-cnt-1)!,对应 arr[n-cnt-1]
                arr_num = arr[n-cnt-1]
                
                # 比较 k 与当前分支的排列数
                for i in range(1, n+1):
                    if used[i]:
                        continue
                    if k > arr_num:
                        # 剪枝
                        # 如果 k 大于当前分支排列数,更新 k,跳过当前分支
                        k -= arr_num
                        continue
                    # 否则,将当前数添加到排列中
                    tmp.append(str(i))
                    used[i] = True
                    # 继续向下选择
                    return dfs(k, tmp)
    
            
            return dfs(k, [])
    

    欢迎关注


    公众号 【书所集录

  • 相关阅读:
    Angular2版本更新
    Angular2组件开发—调用服务(三)
    Angular2组件开发—调用服务(二)
    Angular2组件开发—调用服务(一)
    Angular2组件开发—表单输入(五)
    Angular2组件开发—表单输入(四)
    Angular2组件开发—表单输入(三)
    Angular2组件开发—表单输入(二)
    Angular2组件开发—表单输入(一)
    Angular2组件开发—属性与事件(二)
  • 原文地址:https://www.cnblogs.com/yiluolion/p/13619198.html
Copyright © 2020-2023  润新知