【华为OD-E卷 - 第k个排列 100分(python、java、c++、js、c)】 ...

打印 上一主题 下一主题

主题 1031|帖子 1031|积分 3093

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

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,第二行为 k,
给定 n 的范围是[1, 9], 给定 k 的范围是[1, n!]
输出描述



  • 输出排在第 k 位置的数字
用例

用例一:

输入:

  1. 3
  2. 3
复制代码
输出:

  1. 21
  2. 3
复制代码
用例二:

输入:

  1. 2
  2. 2
复制代码
输出:

  1. 21
复制代码
python解法



  • 解题思绪:
  • 该代码的目的是解决排列组合中的第 k 个排列题目(即字典序第 k 小的排列)。题目描述是:给定正整数 n 和 k,返回从 [1, 2, …, n] 这些数字组成的全部排列中按字典序排列的第 k 个排列。
重要思绪:
使用阶乘数组:通过预盘算阶乘(factorial),快速确定某一位数字对应的索引范围。
按位置逐位构造排列:
确定第 i 位数字时,根据当前剩余排列数量可以盘算该位应该选取的数字。
从剩余数字中取出对应的数字,并从候选数字列表中移除。
递归更新剩余的索引值 k:
盘算余数,缩小题目规模,继续处理剩余的数字
  1. n = int(input())  # 输入 n,表示排列的长度
  2. k = int(input())  # 输入 k,表示需要找的第 k 个排列
  3. # 初始化数字数组 [1, 2, ..., n]
  4. numbers = [i + 1 for i in range(n)]
  5. # 计算阶乘数组,用于快速确定当前数字的索引范围
  6. factorial = [1] * (n + 1)
  7. for i in range(2, n + 1):
  8.     factorial[i] = factorial[i - 1] * i
  9. # 初始化结果数组,用于存储最终的排列结果
  10. result = []
  11. # 因为索引从 0 开始,所以 k 减 1
  12. k -= 1
  13. # 遍历每一位,逐步确定每一位数字
  14. for i in range(1, n + 1):
  15.     # 计算当前位需要选择的数字索引
  16.     index = k // factorial[n - i]
  17.    
  18.     # 将该数字添加到结果数组中
  19.     result.append(str(numbers[index]))
  20.    
  21.     # 从候选数字中移除已选择的数字
  22.     numbers.pop(index)
  23.    
  24.     # 更新 k 的值,缩小问题规模
  25.     k %= factorial[n - i]
  26. # 将结果数组拼接成字符串并输出
  27. print("".join(result))
复制代码
java解法



  • 解题思绪
  • 目的是找到 [1, 2, …, n] 的全部排列中,按字典序排序后的第 k 个排列。解决方式与 Python 版本相似,采用递归的方法逐步构造结果。
重要步调:
使用阶乘的性质确定排列范围:
对于长度为 n 的排列,前 n-1 位的排列总数为 (n-1)!。
根据 (k-1) / (n-1)! 可以盘算出当前排列的起始数字的索引。
递归天生排列:
每次选定一个数字,将其从候选列表中移除。
根据剩余的 k 值,递归处理剩下的数字。
拼接结果:
每次递归选出的数字依次拼接,终极形成完整的排列。
  1. import java.util.ArrayList;
  2. import java.util.List;
  3. import java.util.Scanner;
  4. public class Main {
  5.     public static void main(String[] args) {
  6.         Scanner sc = new Scanner(System.in); // 创建输入对象
  7.         int n = sc.nextInt(); // 输入 n,表示排列的长度
  8.         int k = sc.nextInt(); // 输入 k,表示需要找的第 k 个排列
  9.         List<Integer> nums = new ArrayList<>(); // 初始化数字列表 [1, 2, ..., n]
  10.         for (int i = 1; i <= n; i++) nums.add(i);
  11.         // 调用函数获取第 k 个排列并输出
  12.         System.out.println(getPermutation(nums, k));
  13.     }
  14.     /**
  15.      * 获取第 k 个排列
  16.      * @param nums 候选数字列表
  17.      * @param k    第 k 个排列(从 1 开始)
  18.      * @return     第 k 个排列的字符串
  19.      */
  20.     public static String getPermutation(List<Integer> nums, int k) {
  21.         // 如果列表为空,返回空字符串(递归终止条件)
  22.         if (nums.size() == 0) return "";
  23.         int n = nums.size(); // 当前列表的长度
  24.         int f = factorial(n - 1); // 计算 (n-1)!,用于确定当前数字的范围
  25.         int index = (k - 1) / f; // 确定当前位数字的索引
  26.         int chosen = nums.remove(index); // 从候选数字列表中移除选择的数字
  27.         k = k - index * f; // 更新 k,处理剩余部分
  28.         // 返回当前选择的数字和剩余数字的排列结果
  29.         return chosen + getPermutation(nums, k);
  30.     }
  31.     /**
  32.      * 计算 n 的阶乘
  33.      * @param n 非负整数
  34.      * @return  n 的阶乘
  35.      */
  36.     public static int factorial(int n) {
  37.         int result = 1; // 初始化结果为 1
  38.         for (int i = 2; i <= n; i++) result *= i; // 从 2 开始累乘到 n
  39.         return result;
  40.     }
  41. }
复制代码
C++解法



  • 解题思绪

  1. 更新中
复制代码
C解法



  • 解题思绪

  1. 更新中
复制代码
JS解法



  • 解题思绪
  • 问标题标是找到从 [1, 2, …, n] 这些数字中天生的全部排列中,按字典序第 k 小的排列。代码使用了贪心算法结合数学分析来高效解决该题目。
核心思绪:
使用阶乘的性质分割排列范围:
如果第一个数字固定为某值,那么剩下的排列数是 (n-1)!。
使用 k / (n-1)! 可以快速确定当前位的数字是哪一个。
动态更新数字列表:
每次确定一位数字后,将其从候选数字列表中移除。
逐步缩小题目规模:
更新 k 的值为当前范围内的余数,递归处理剩余的排列题目。
边界处理:
当数字列表为空时,递归终止
  1. const readline = require('readline'); // 引入 readline 模块处理标准输入输出
  2. const rl = readline.createInterface({
  3.     input: process.stdin,
  4.     output: process.stdout
  5. });
  6. rl.on('line', (input) => {
  7.     // 处理输入,第一行为 n,第二行为 k
  8.     if (!global.n) {
  9.         global.n = parseInt(input.trim()); // 读取 n
  10.     } else {
  11.         global.k = parseInt(input.trim()); // 读取 k
  12.         console.log(getKthPermutation(global.n, global.k)); // 输出第 k 个排列
  13.         rl.close(); // 关闭输入流
  14.     }
  15. });
  16. /**
  17. * 获取第 k 个排列
  18. * @param {number} n - 数字范围 1 到 n
  19. * @param {number} k - 第 k 个排列(从 1 开始)
  20. * @return {string} 返回第 k 个排列的字符串
  21. */
  22. function getKthPermutation(n, k) {
  23.     let factorials = [1]; // 用于存储阶乘值
  24.     let nums = []; // 候选数字列表
  25.     // 初始化阶乘数组和候选数字列表
  26.     for (let i = 1; i <= n; i++) {
  27.         factorials[i] = factorials[i - 1] * i; // 计算并存储 i 的阶乘
  28.         nums.push(i); // 将数字 i 加入候选数字列表
  29.     }
  30.     k--; // 将 k 转换为从 0 开始的索引
  31.     let result = ''; // 存储最终结果的字符串
  32.     // 从高位到低位依次确定每一位数字
  33.     for (let i = n; i > 0; i--) {
  34.         // 确定当前位数字的索引
  35.         let idx = Math.floor(k / factorials[i - 1]);
  36.         result += nums[idx]; // 将选定的数字添加到结果字符串中
  37.         nums.splice(idx, 1); // 从候选数字列表中移除该数字
  38.         k %= factorials[i - 1]; // 更新 k 的值为余数
  39.     }
  40.     return result; // 返回最终结果
  41. }
复制代码
注意:

如果发现代码有用例覆盖不到的情况,接待反馈!会在第一时间修正,更新。
解题不易,如对您有帮助,接待点赞/收藏

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

数据人与超自然意识

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表