#P3063. 第k个排列(100分)
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 130
            Accepted: 54
            Difficulty: 3
            
          
          
          
                       所属公司 : 
                              华为od
                                
            
                      
          
 
- 
                        算法标签>数学          
 
第k个排列(100分)
题面描述
给定参数n,从1到n会有n个整数:1,2,3......n。这n个数字共有n!种排列。我们需要按大小顺序升序列出所有排列的情况,并一一标记。给定n和k,返回第k个排列。
解题思路
- 
排列生成的性质:
- 任何n的排列都可以通过固定某个数字,剩余的数字再进行全排列来生成。
 - 比如,对于n=3,固定数字1,则其余2的排列为2,3。
 
 - 
排列数量:
- 每个数字固定后,其余n−1个数字的排列数为(n−1)!。
 - 因此,我们可以根据k的值判断第一个数字应该是哪个,从而逐步缩小范围。
 
 - 
具体步骤:
- 计算(n−1)!。
 - 根据k找到对应的第一个数字。
 - 从可用的数字中移除已选的数字,继续对剩下的数字进行同样的操作,直到所有数字都被选择。
 
 
代码分析
- 
factorial 函数:
- 递归计算给定数字n的阶乘。
 
 - 
getPermutation 函数:
- 初始化一个可选数字的数组 
numbers,包含1到n的所有整数。 - 通过循环确定每一个数字的位置,直到构建出完整的排列字符串。
 - 在每一步中,根据当前k的值和当前剩余数字的排列数量,确定下一个数字,并从 
numbers中移除该数字。 
 - 初始化一个可选数字的数组 
 - 
主函数:
- 读取输入,调用 
getPermutation函数并输出结果。 
 - 读取输入,调用 
 
cpp
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// 计算阶乘
int factorial(int n) {
    return (n == 1 || n == 0) ? 1 : factorial(n - 1) * n;
}
string getPermutation(int n, int k) {
    vector<int> numbers;
    // 初始化可选数字
    for (int i = 1; i <= n; i++) {
        numbers.push_back(i);
    }
    string permutation = "";
    k--; // k 从 1 开始计数,转为 0 开始计数
    // 逐步构建排列
    for (int i = 0; i < n; i++) {
        int fact = factorial(n - 1 - i); // 计算 (n-i-1)!
        int index = k / fact; // 找到当前数字的索引
        permutation += to_string(numbers[index]); // 添加到结果中
        numbers.erase(numbers.begin() + index); // 移除已选数字
        k %= fact; // 更新 k
    }
    return permutation;
}
int main() {
    int n, k;
    cin >> n >> k;
    cout << getPermutation(n, k) << endl;
    return 0;
}
python
def factorial(n):
    if n == 1 or n == 0:
        return 1
    return factorial(n - 1) * n
def get_permutation(n, k):
    numbers = list(range(1, n + 1))  # 初始化可选数字
    permutation = ""
    k -= 1  # k 从 1 开始计数,转为 0 开始计数
    # 逐步构建排列
    for i in range(n):
        fact = factorial(n - 1 - i)  # 计算 (n-i-1)!
        index = k // fact  # 找到当前数字的索引
        permutation += str(numbers[index])  # 添加到结果中
        numbers.pop(index)  # 移除已选数字
        k %= fact  # 更新 k
    return permutation
if __name__ == "__main__":
    n = int(input())
    k = int(input())
    print(get_permutation(n, k))
java
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Permutation {
    
    // 计算阶乘
    public static int factorial(int n) {
        if (n == 1 || n == 0) {
            return 1;
        }
        return factorial(n - 1) * n;
    }
    // 获取第 k 个排列
    public static String getPermutation(int n, int k) {
        List<Integer> numbers = new ArrayList<>();
        // 初始化可选数字
        for (int i = 1; i <= n; i++) {
            numbers.add(i);
        }
        StringBuilder permutation = new StringBuilder();
        k--; // k 从 1 开始计数,转为 0 开始计数
        // 逐步构建排列
        for (int i = 0; i < n; i++) {
            int fact = factorial(n - 1 - i); // 计算 (n-i-1)!
            int index = k / fact; // 找到当前数字的索引
            permutation.append(numbers.get(index)); // 添加到结果中
            numbers.remove(index); // 移除已选数字
            k %= fact; // 更新 k
        }
        return permutation.toString();
    }
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int k = scanner.nextInt();
        System.out.println(getPermutation(n, k));
        scanner.close();
    }
}
        题目内容
给定参数 n,从 1 到 n 会有 n 个整数:1,2,3,…,n, 这 n 个数字共有 n! 种排列。
按大小顺序升序列出所有排列的情况,并一一标记,当 n = 3 时,所有排列如下:
- “123”
 - “132”
 - “213”
 - “231”
 - “312”
 - “321”
 
给定 n 和 k,返回第 k 个排列。
输入描述
输入两行,第一行为 n,第二行为 k,
给定 n 的范围是[1,9], 给定 k 的范围是[1,n!]。
输出描述
输出排在第 k 位置的数字。
样例1
输入
3
3
输出
213
说明
3的排列有123,132,213,…,那么第三位置就是213
样例2
输入
2
2
输出
21
说明
2的排列有12,21,那么第二位置的为21。