【困难】题解力扣60:排列序列

题目详情

给出集合 [1,2,3,...,n],其所有元素共有 n! 种排列。按大小顺序列出所有排列情况,并一一标记,当 n = 3 时,所有排列如下:

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

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

示例 1:
输入:n = 3, k = 3
输出:“213”

示例 2:
输入:n = 4, k = 9
输出:“2314”

示例 3:
输入:n = 3, k = 1
输出:“123”

提示:

  • 1 <= n <= 9
  • 1 <= k <= n!

解题思路

为了高效解决这个问题,我们使用数学方法直接计算第 k 个排列,避免枚举所有排列。核心思路是逐位确定排列中的每个数字:

  1. 预处理阶乘值:计算 0!(n-1)! 的值,用于后续计算每个位置的数字。
  2. 可用数字列表:初始化一个包含数字 1n 的列表。
  3. 索引调整:将 k 减 1(因为排列索引从 0 开始)。
  4. 逐位确定数字
    • 对于第 i 位(i0 开始),剩余数字个数为 m = n - i
    • 计算当前数字在剩余数字列表中的索引:index = k / (m-1)!
    • 从列表中取出该索引对应的数字,移除该数字。
    • 更新 kk = k % (m-1)!
  5. 组合结果:将每次取出的数字组合成最终排列字符串。

数学原理

  • 对于 n 个数字的排列,第一位有 n 种选择,每种选择对应 (n-1)! 种排列。
  • 通过 k / (n-1)! 可以确定第一位的数字索引。
  • 更新 k 为余数后,递归处理剩余数字,直至确定所有位。

代码实现(Java版)

class Solution {
    public String getPermutation(int n, int k) {
        // 计算0!到(n-1)!的阶乘数组
        int[] factorial = new int[n];
        factorial[0] = 1; // 0! = 1
        for (int i = 1; i < n; i++) {
            factorial[i] = factorial[i - 1] * i;
        }
        
        // 初始化可用数字列表(1~n)
        List<Integer> nums = new ArrayList<>();
        for (int i = 1; i <= n; i++) {
            nums.add(i);
        }
        
        // 调整k为从0开始的索引
        k--;
        
        StringBuilder result = new StringBuilder();
        // 逐位确定数字
        for (int i = n - 1; i >= 0; i--) {
            // 计算当前位的索引
            int index = k / factorial[i];
            // 取出该索引对应的数字并移除
            result.append(nums.remove(index));
            // 更新k为余数
            k %= factorial[i];
        }
        
        return result.toString();
    }
}

代码说明

  1. 阶乘数组初始化

    • factorial[i] 存储 i! 的值(i0n-1)。
    • 例如 n=4 时,factorial = [1, 1, 2, 6](对应 0!, 1!, 2!, 3!)。
  2. 可用数字列表

    • 初始化为 [1, 2, ..., n],每次确定一位后移除已使用的数字。
  3. 索引调整

    • k 减 1 转换为从 0 开始的索引(例如第 1 个排列视为索引 0)。
  4. 循环确定每位数字

    • 索引计算index = k / factorial[i] 确定当前位在剩余数字中的位置。
    • 更新列表:从列表中移除已使用的数字。
    • 更新余数k = k % factorial[i] 用于计算下一位。
  5. 时间复杂度:O(n²),其中:

    • 外层循环 O(n)。
    • 列表移除操作 O(n)(ArrayListremove 方法平均 O(n))。
  6. 空间复杂度:O(n),用于存储阶乘数组和数字列表。


提交详情(执行用时、内存消耗)

【困难】题解力扣60:排列序列_第1张图片

感谢大家的阅读,我的力扣算法题解专栏正在持续更新,欢迎大家订阅!!如果觉得这篇内容对你有帮助,别忘了点赞+收藏+关注哦!!你的支持,将是我创作的最大动力

你可能感兴趣的:(力扣算法:题海战术,算法,leetcode,java)