网上做网站任务欧模网
题目描述
给定整数 n 和 k,返回由 1 到 n 组成的排列中第 k 个排列。
- 所有排列按字典序排列。
 1 ≤ n ≤ 9,1 ≤ k ≤ n!。
解题思路
要快速找到第 k 个排列,可以利用数学方法而不是生成所有排列:
1. 知识点:阶乘与字典序
- 对于给定的 
n,共有n!种排列。 - 每个数字作为排列的起点时,其后续排列数为 
(n-1)!。 - 利用这一规律,可以逐步确定排列的每一位。
 
2. 数学推导
-  
确定第 1 位:
k以(n-1)!为单位划分。- 第一个数字是 
(k-1)/(n-1)! + 1。 - 更新 
k = k % (n-1)!。 
 -  
重复确定后续数字:
- 每次缩小范围,使用相同的逻辑继续计算。
 
 -  
数字选择:
- 使用一个列表存储可选的数字,每次选中一个后移除。
 
 
3. 算法步骤
- 计算阶乘数组,用于快速获取 
(n-1)!。 - 使用数字列表维护当前可以使用的数字。
 - 根据 
k确定每一位数字。 
C 语言代码实现
以下是完整的 C 语言实现:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 主函数:获取第 k 个排列
char* getPermutation(int n, int k) {// 计算阶乘数组int factorial[n];factorial[0] = 1;for (int i = 1; i < n; i++) {factorial[i] = factorial[i - 1] * i;}// 可选数字列表int numbers[n];for (int i = 0; i < n; i++) {numbers[i] = i + 1; // 初始为 [1, 2, ..., n]}// 分配结果字符串char* result = (char*)malloc((n + 1) * sizeof(char));result[n] = '\0'; // 末尾加结束符// 调整为从 0 开始的索引k--;// 构造排列for (int i = 0; i < n; i++) {int index = k / factorial[n - 1 - i]; // 当前数字的索引result[i] = numbers[index] + '0';    // 转为字符// 删除已选数字for (int j = index; j < n - i - 1; j++) {numbers[j] = numbers[j + 1];}k %= factorial[n - 1 - i]; // 更新 k}return result;
}// 测试代码
int main() {int n = 4, k = 9;char* result = getPermutation(n, k);printf("第 %d 个排列是: %s\n", k, result);free(result); // 释放内存return 0;
}
 
代码解析
-  
阶乘数组的计算:
factorial[0] = 1; for (int i = 1; i < n; i++) {factorial[i] = factorial[i - 1] * i; }- 用于快速获取 
(n-1)!。 
 - 用于快速获取 
 -  
维护可选数字:
for (int i = 0; i < n; i++) {numbers[i] = i + 1; }- 初始数字列表为 
[1, 2, ..., n]。 - 每选定一个数字后,从列表中移除。
 
 - 初始数字列表为 
 -  
逐步构造排列:
int index = k / factorial[n - 1 - i]; // 当前数字的索引 result[i] = numbers[index] + '0'; // 转为字符- 根据 
k确定当前位的数字索引。 - 将对应数字从 
numbers中移除,更新k。 
 - 根据 
 -  
更新索引
k:k %= factorial[n - 1 - i];- 剩余排列数更新为当前范围内的相对位置。
 
 -  
构造字符串:
- 动态分配内存存储结果,并在末尾添加字符串结束符。
 
 
复杂度分析
-  
时间复杂度:
- 阶乘数组计算:
O(n)。 - 每次确定一位数字需移除列表中的一个元素:
O(n^2)。 - 总复杂度为 
O(n^2)。 
 - 阶乘数组计算:
 -  
空间复杂度:
- 需要额外的 
O(n)空间存储数字列表和阶乘数组。 
 - 需要额外的 
 
测试案例
输入:
n = 4, k = 9
 
输出:
"2314"
 
输入:
n = 3, k = 3
 
输出:
"213"
