news 2026/7/10 3:22:33

(新卷,100分)- 第k个排列(Java JS Python)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
(新卷,100分)- 第k个排列(Java JS Python)

(新卷,100分)- 第k个排列(Java & JS & Python)

题目描述

给定参数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位置的数字。

用例
输入

3
3

输出213
说明3的排列有123,132,213…,那么第三位置就是213
输入

2
2

输出21
说明2的排列有12,21,那么第二位置的为21。
题目解析

通过上面n=3的全排列可以分析,以1开头、以2开头、以3开头的排列个数各有两个,因为固定开头为1的,则其排列情况就是n=2的排列情况,即有两个23、32。

因此以1开头的排列个数有 2!个,以2,3开头的排列个数求解同理。

因此我们要求n=3的第k个排列,完全可以推断出第k个排列的开头数字是几。

比如n=3的第1个和第2个排列的开头数字prefix就是1,第3、4个排列的开头数字prefix就是2,第5、6个排列的开头数字prefix就是3。

推导一下,可得公式:Math.ceil(k / (n-1)!)

但是这里我不想根据k、n来直接推导出排列的开头数字prefix,因为这个逻辑不适用于后面的递归,我们会将组成排列的数字按大小升序存入一个数组 arr中,比如n=3的排列元素为 arr = [1,2,3],此时我们要求n=3的第k个排列的开头数字,公式为:arr [ Math.floor((k-1) / (n-1)!) ]

知道了第k个排列的开头数字prefix后,我们就可以缩小排列的查找范围,比如n=3,k=3的排列查找就可以在以下范围中查找:

  • 213
  • 231

而此时k=3值就不适用了,因为k=3是相对于下面情况的

  • 123
  • 132
  • 213
  • 231
  • 312
  • 321

我们需要将k值转换为1,转换公式如下:

newK = k % (n-1)!

但是这个公式不普适,比如n=3,k=4时,经过上面公式转换newK就变为0,而实际上newK应该为2,因此我们需要附加判断

newK === 0 ? (n-1)! : newK

此时就完成了大问题

n=3, k=3, arr=[1,2,3]

的简化,简化为了

n=2, k=1 ,arr=[1,3] 且 prefix=2

因此我们可以使用递归来解决此题,而当k=1时,表示当前arr=[1,3]的排列就是需要的排列,因此最终要找的排列就是 prefix + arr.join('') = 213。

因此 k =1就是递归的出口条件。

Java算法源码
import java.util.Arrays; import java.util.Scanner; public class Main { static int[] fact; public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int k = sc.nextInt(); fact = new int[n + 1]; fact[1] = 1; for (int i = 2; i <= n; i++) { fact[i] = fact[i - 1] * i; } int[] arr = new int[n]; for (int i = 0; i < n; i++) arr[i] = i + 1; System.out.println(getNK(n, k, arr)); } public static String getNK(int n, int k, int[] arr) { if (n == 1) return "1"; int f = fact[n - 1]; int prefix = arr[(k - 1) / f]; k %= f; k = k == 0 ? f : k; arr = Arrays.stream(arr).filter(ele -> ele != prefix).toArray(); if (k == 1) { StringBuilder sb = new StringBuilder(); for (int v : arr) sb.append(v); return prefix + sb.toString(); } else { return prefix + getNK(n - 1, k, arr); } } }
JS算法源码
/* JavaScript Node ACM模式 控制台输入获取 */ const readline = require("readline"); const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); const lines = []; let factorial = [0, 1]; rl.on("line", (line) => { lines.push(line); if (lines.length === 2) { let [n, k] = lines.map((ele) => parseInt(ele)); for (let i = 2; i <= n; i++) { factorial[i] = factorial[i - 1] * i; } let arr = new Array(n).fill(0).map((_, index) => index + 1); console.log(getNK(n, k, arr)); lines.length = 0; } }); /* 算法 */ function getNK(n, k, arr) { if (n === 1) { return "1"; } let f = factorial[n - 1]; let prefix = arr[Math.floor((k - 1) / f)]; k = k % f; k = k === 0 ? f : k; arr = arr.filter((ele) => ele !== prefix); if (k === 1) { return prefix + arr.join(""); } else { return prefix + getNK(n - 1, k, arr); } }
Python算法源码
# 输入获取 n = int(input()) k = int(input()) arr = [i + 1 for i in range(n)] fact = [0] * (n + 1) fact[1] = 1 for i in range(2, n + 1): fact[i] = fact[i - 1] * i # 算法入口 def getResult(n, k, arr): if n == 1: return "1" f = fact[n - 1] prefix = arr[(k - 1) // f] k %= f k = f if k == 0 else k arr = list(filter(lambda x: x != prefix, arr)) if k == 1: return str(prefix) + "".join(map(str, arr)) else: return str(prefix) + getResult(n - 1, k, arr) # 算法调用 print(getResult(n, k, arr))
解法二:不用递归
Java算法源码
import java.util.Arrays; import java.util.Scanner; public class Main { static int[] fact; public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int k = sc.nextInt(); fact = new int[n + 1]; fact[1] = 1; for (int i = 2; i <= n; i++) { fact[i] = fact[i - 1] * i; } int[] arr = new int[n]; for (int i = 0; i < n; i++) arr[i] = i + 1; System.out.println(getResult(n, k, arr)); } public static String getResult(int n, int k, int[] arr) { if (n == 1) return "1"; StringBuilder sb = new StringBuilder(); while (true) { int f = fact[n - 1]; int prefix = arr[(k - 1) / f]; sb.append(prefix); k = k % f; if (k == 0) k = f; arr = Arrays.stream(arr).filter(ele -> ele != prefix).toArray(); n--; if (k == 1) { for (int v : arr) sb.append(v); break; } } return sb.toString(); } }
JS算法源码
/* JavaScript Node ACM模式 控制台输入获取 */ const readline = require("readline"); const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); const lines = []; rl.on("line", (line) => { lines.push(line); if (lines.length === 2) { let [n, k] = lines.map((ele) => parseInt(ele)); console.log(getPermutation(n, k)); lines.length = 0; } }); function getPermutation(n, k) { if (n === 1) return "1"; // 记录n!排列组合需要的成员 let arr = new Array(n).fill(0).map((_, idx) => idx + 1); // 记录阶乘值 let factorial = [0, 1]; for (let i = 2; i <= n; i++) { factorial[i] = factorial[i - 1] * i; } let res = ""; while (true) { // 第k个排列的开头数字prefix let prefix = arr[Math.floor((k - 1) / factorial[n - 1])]; res += prefix; // 对应排列在开头为prefix的排列中的序号 k = k % factorial[n - 1]; if (k === 0) { k = factorial[n - 1]; } // 开头为prefix的排列所需的成员 arr = arr.filter((ele) => ele !== prefix); n--; if (k === 1) { res += arr.join(""); break; } } return res; }
Python算法源码
# 输入获取 n = int(input()) k = int(input()) arr = [i + 1 for i in range(n)] fact = [0] * (n + 1) fact[1] = 1 for i in range(2, n + 1): fact[i] = fact[i - 1] * i # 算法入口 def getResult(n, k, arr): if n == 1: return "1" res = [] while True: prefix = arr[(k - 1) // fact[n-1]] res.append(str(prefix)) k = k % fact[n-1] if k == 0: k = fact[n-1] arr = list(filter(lambda x: x != prefix, arr)) n -= 1 if k == 1: res.append("".join(map(str, arr))) break return "".join(res) # 算法调用 print(getResult(n, k, arr))
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/8 6:35:22

社会网络仿真软件:NetLogo_(4).NetLogo编程基础

NetLogo编程基础 在这一节中&#xff0c;我们将详细介绍NetLogo编程的基础知识&#xff0c;包括NetLogo的基本概念、环境设置、编程语言特性以及如何创建和运行简单的模型。通过这一节的学习&#xff0c;您将能够掌握NetLogo的基本编程技巧&#xff0c;为后续的复杂模型开发打下…

作者头像 李华
网站建设 2026/7/8 6:35:28

社会网络仿真软件:NetLogo_(6).数据导入与导出

数据导入与导出 在社会网络仿真软件NetLogo中&#xff0c;数据导入与导出是两个非常重要的功能&#xff0c;它们使得仿真模型能够与外部数据进行交互&#xff0c;从而增强模型的灵活性和实用性。通过数据导入&#xff0c;用户可以从外部文件中加载数据&#xff0c;用于初始化模…

作者头像 李华
网站建设 2026/7/1 9:15:04

【Matlab】MATLAB矩阵子矩阵索引详解:从语法案例到分块应用

MATLAB矩阵子矩阵索引详解:从语法案例到分块应用 在MATLAB矩阵操作体系中,子矩阵索引是比整行/列索引更灵活的核心技能,能够精准提取矩阵中任意连续或离散的子区域数据。无论是数据分块处理、局部特征提取,还是复杂数值计算中的区域运算,子矩阵索引都发挥着不可替代的作用…

作者头像 李华
网站建设 2026/7/1 8:45:42

Clawedbot 完整对接飞书教程 手把手搭建你的专属 AI 助手

Clawedbot 完整对接飞书教程 手把手搭建你的专属 AI 助手 注意本教程在 Linux 系统下进行 Clawdbot 由于 Claude 的版权问题&#xff0c;已更名为 Moltbot&#xff0c;因此本教程基于最新版本编写。下面进入安装流程 首先准备一台闲置的云服务器或 VPS&#xff08;推荐使用香港…

作者头像 李华
网站建设 2026/7/1 10:29:07

程序员如何利用AI进行数据可视化

程序员如何利用AI进行数据可视化 关键词:程序员、AI、数据可视化、算法原理、应用场景 摘要:本文旨在为程序员提供全面且深入的指导,详细阐述如何利用AI进行数据可视化。首先介绍相关背景知识,包括目的范围、预期读者等内容。接着讲解核心概念与联系,通过文本示意图和Merm…

作者头像 李华
网站建设 2026/7/1 8:45:47

GitHub MCP

在TRAE中集成GitHub MCP&#xff0c;相当于给你的AI助手配备了一套可以直接查询、操作GitHub仓库的专业工具。这能让AI在理解你的项目背景、生成相关代码或操作建议时&#xff0c;获得更精确的上下文。&#x1f527; 配置GitHub MCP Server你需要准备一个GitHub Personal Acces…

作者头像 李华