马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
【华为OD-E卷 - 第k个排列 100分(python、java、c++、js、c)】
标题
给定参数 n,从 1 到 n 会有 n 个整数:1,2,3,…,n, 这 n 个数字共有 n! 种排列。
按巨细顺序升序列出全部排列的情况,并一一标记,当 n = 3 时,全部排列如下:
“123” “132” “21
3
” “231” “312” “321
” 给定 n 和 k,返回第 k 个排列
输入描述
给定 n 的范围是[1, 9], 给定 k 的范围是[1, n!]
输出描述
用例
用例一:
输入:
输出:
用例二:
输入:
输出:
python解法
- 解题思绪:
- 该代码的目的是解决排列组合中的第 k 个排列题目(即字典序第 k 小的排列)。题目描述是:给定正整数 n 和 k,返回从 [1, 2, …, n] 这些数字组成的全部排列中按字典序排列的第 k 个排列。
重要思绪:
使用阶乘数组:通过预盘算阶乘(factorial),快速确定某一位数字对应的索引范围。
按位置逐位构造排列:
确定第 i 位数字时,根据当前剩余排列数量可以盘算该位应该选取的数字。
从剩余数字中取出对应的数字,并从候选数字列表中移除。
递归更新剩余的索引值 k:
盘算余数,缩小题目规模,继续处理剩余的数字
- n = int(input()) # 输入 n,表示排列的长度
- k = int(input()) # 输入 k,表示需要找的第 k 个排列
- # 初始化数字数组 [1, 2, ..., n]
- numbers = [i + 1 for i in range(n)]
- # 计算阶乘数组,用于快速确定当前数字的索引范围
- factorial = [1] * (n + 1)
- for i in range(2, n + 1):
- factorial[i] = factorial[i - 1] * i
- # 初始化结果数组,用于存储最终的排列结果
- result = []
- # 因为索引从 0 开始,所以 k 减 1
- k -= 1
- # 遍历每一位,逐步确定每一位数字
- for i in range(1, n + 1):
- # 计算当前位需要选择的数字索引
- index = k // factorial[n - i]
-
- # 将该数字添加到结果数组中
- result.append(str(numbers[index]))
-
- # 从候选数字中移除已选择的数字
- numbers.pop(index)
-
- # 更新 k 的值,缩小问题规模
- k %= factorial[n - i]
- # 将结果数组拼接成字符串并输出
- print("".join(result))
复制代码 java解法
- 解题思绪
- 目的是找到 [1, 2, …, n] 的全部排列中,按字典序排序后的第 k 个排列。解决方式与 Python 版本相似,采用递归的方法逐步构造结果。
重要步调:
使用阶乘的性质确定排列范围:
对于长度为 n 的排列,前 n-1 位的排列总数为 (n-1)!。
根据 (k-1) / (n-1)! 可以盘算出当前排列的起始数字的索引。
递归天生排列:
每次选定一个数字,将其从候选列表中移除。
根据剩余的 k 值,递归处理剩下的数字。
拼接结果:
每次递归选出的数字依次拼接,终极形成完整的排列。
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Scanner;
- public class Main {
- public static void main(String[] args) {
- Scanner sc = new Scanner(System.in); // 创建输入对象
- int n = sc.nextInt(); // 输入 n,表示排列的长度
- int k = sc.nextInt(); // 输入 k,表示需要找的第 k 个排列
- List<Integer> nums = new ArrayList<>(); // 初始化数字列表 [1, 2, ..., n]
- for (int i = 1; i <= n; i++) nums.add(i);
- // 调用函数获取第 k 个排列并输出
- System.out.println(getPermutation(nums, k));
- }
- /**
- * 获取第 k 个排列
- * @param nums 候选数字列表
- * @param k 第 k 个排列(从 1 开始)
- * @return 第 k 个排列的字符串
- */
- public static String getPermutation(List<Integer> nums, int k) {
- // 如果列表为空,返回空字符串(递归终止条件)
- if (nums.size() == 0) return "";
- int n = nums.size(); // 当前列表的长度
- int f = factorial(n - 1); // 计算 (n-1)!,用于确定当前数字的范围
- int index = (k - 1) / f; // 确定当前位数字的索引
- int chosen = nums.remove(index); // 从候选数字列表中移除选择的数字
- k = k - index * f; // 更新 k,处理剩余部分
- // 返回当前选择的数字和剩余数字的排列结果
- return chosen + getPermutation(nums, k);
- }
- /**
- * 计算 n 的阶乘
- * @param n 非负整数
- * @return n 的阶乘
- */
- public static int factorial(int n) {
- int result = 1; // 初始化结果为 1
- for (int i = 2; i <= n; i++) result *= i; // 从 2 开始累乘到 n
- return result;
- }
- }
复制代码 C++解法
C解法
JS解法
- 解题思绪
- 问标题标是找到从 [1, 2, …, n] 这些数字中天生的全部排列中,按字典序第 k 小的排列。代码使用了贪心算法结合数学分析来高效解决该题目。
核心思绪:
使用阶乘的性质分割排列范围:
如果第一个数字固定为某值,那么剩下的排列数是 (n-1)!。
使用 k / (n-1)! 可以快速确定当前位的数字是哪一个。
动态更新数字列表:
每次确定一位数字后,将其从候选数字列表中移除。
逐步缩小题目规模:
更新 k 的值为当前范围内的余数,递归处理剩余的排列题目。
边界处理:
当数字列表为空时,递归终止
- const readline = require('readline'); // 引入 readline 模块处理标准输入输出
- const rl = readline.createInterface({
- input: process.stdin,
- output: process.stdout
- });
- rl.on('line', (input) => {
- // 处理输入,第一行为 n,第二行为 k
- if (!global.n) {
- global.n = parseInt(input.trim()); // 读取 n
- } else {
- global.k = parseInt(input.trim()); // 读取 k
- console.log(getKthPermutation(global.n, global.k)); // 输出第 k 个排列
- rl.close(); // 关闭输入流
- }
- });
- /**
- * 获取第 k 个排列
- * @param {number} n - 数字范围 1 到 n
- * @param {number} k - 第 k 个排列(从 1 开始)
- * @return {string} 返回第 k 个排列的字符串
- */
- function getKthPermutation(n, k) {
- let factorials = [1]; // 用于存储阶乘值
- let nums = []; // 候选数字列表
- // 初始化阶乘数组和候选数字列表
- for (let i = 1; i <= n; i++) {
- factorials[i] = factorials[i - 1] * i; // 计算并存储 i 的阶乘
- nums.push(i); // 将数字 i 加入候选数字列表
- }
- k--; // 将 k 转换为从 0 开始的索引
- let result = ''; // 存储最终结果的字符串
- // 从高位到低位依次确定每一位数字
- for (let i = n; i > 0; i--) {
- // 确定当前位数字的索引
- let idx = Math.floor(k / factorials[i - 1]);
- result += nums[idx]; // 将选定的数字添加到结果字符串中
- nums.splice(idx, 1); // 从候选数字列表中移除该数字
- k %= factorials[i - 1]; // 更新 k 的值为余数
- }
- return result; // 返回最终结果
- }
复制代码 注意:
如果发现代码有用例覆盖不到的情况,接待反馈!会在第一时间修正,更新。
解题不易,如对您有帮助,接待点赞/收藏
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |