《程序员数学:排列》有重复与无重复排列的 Java 递归实现与复杂度解析
《程序员数学排列》有重复与无重复排列的 Java 递归实现与复杂度解析【免费下载链接】CodeGuide:books: 本代码库是作者小傅哥多年从事一线互联网 Java 开发的学习历程技术汇总旨在为大家提供一个清晰详细的学习教程侧重点更倾向编写Java核心内容。如果本仓库能为您提供帮助请给予支持(关注、点赞、分享)项目地址: https://gitcode.com/gh_mirrors/code/CodeGuide排列Permutation是高中阶段最常见的组合数学问题之一给定n个元素在“可重复使用”与“不可重复使用”两种约束下分别能组成多少种、以及如何枚举出全部排列结果。本文以 CodeGuide 仓库中 排列算法文档 为核心骨架完整讲解n!与n^r两条计数公式背后的 Java 递归实现并结合仓库内阶乘、组合、笛卡尔积等同系列算法文档进行纵向对照帮助你既会算、也能写、更能分析复杂度。一、前言从“高中排列题”到“程序员算法”有A、B、C三个字母允许重复使用字母与不允许重复使用字母分别有多少种组合方式这是高中阶段非常常见的数学问题答案可以用公式直接算出不可重复组合数n * (n-1) * (n - 2) * ... * 1 n!可重复组合数n * n * n ...共 r 次 n^r例如{1, 2, 3}三个元素无重复排列全排列数量为3! 6有重复排列长度为 2数量为3^2 9。这类计算本身并不难但作为程序员我们常常需要把这样的数学问题用代码逻辑真实地枚举出来——即不仅算出“有多少种”还要把每一种排列结果都构造出来。同时还需要考虑一个核心问题时间复杂度。本文接下来就以 CodeGuide 仓库中 排列算法文档 给出的两份 Java 实现为主线逐行拆解其递归过程并验证运行结果。二、数学基础排列计数公式与阶乘的关系排列问题的本质是“从n个不同元素中按顺序选取r个元素”约束计数公式含义无重复排列n! / (n - r)!全排列时为n!每个元素最多使用一次顺序有意义有重复排列n^r每个位置都有n种选择元素可重复使用其中n!阶乘是排列计算的基石其递推关系为n! n · (n-1)!关于阶乘的定义、递归实现与测试可参考仓库中的 《程序员数学阶乘》。理解这两个公式后就可以进入代码实现环节。需要特别说明的是方法名才是语义的权威——permutationWithRepetitions对应“有重复排列”permutationWithoutRepetitions对应“无重复排列”这一点在原文档的两个小节标题命名上存在倒置我们以下文的代码与测试输出为准展开。三、有重复排列permutationWithRepetitions1. 完整实现public static ListListInteger permutationWithRepetitions(int[] permutationOptions, int permutationLength) { if (permutationLength 1) { ListListInteger result new ArrayList(); for (int permutationOption : permutationOptions) { ListInteger item new ArrayList(); item.add(permutationOption); result.add(item); } return result; } ListListInteger permutations new ArrayList(); ListListInteger smallerPermutations permutationWithRepetitions(permutationOptions, permutationLength - 1); for (int currentOption : permutationOptions) { for (ListInteger smallerPermutation : smallerPermutations) { ListInteger permutation new ArrayList(); permutation.add(currentOption); permutation.addAll(smallerPermutation); permutations.add(permutation); } } return permutations; }2. 参数与递归逻辑拆解permutationOptions可供选择的元素数组permutationLength目标排列的长度即公式中的r例如从{1, 2, 3}中取长度为 2 的排列。算法采用自顶向下的递归策略核心分三步递归出口base case当permutationLength 1时把permutationOptions中的每个元素分别包装成单元素列表返回即r 1时共有n个排列递归降维先递归调用permutationWithRepetitions(permutationOptions, permutationLength - 1)求出所有长度为r-1的“小排列”前插合并外层遍历permutationOptions的每一个元素currentOption把它前插到每一个小排列的最前面从而生成长度为r的完整排列。由于每次递归都会把全部n个元素与所有r-1长度的小排列做一次笛卡尔式拼接最终生成的结果数量恰为n^r与公式完全吻合。3. 递归过程示例{1, 2, 3}长度 2r 1返回[1]、[2]、[3]r 2依次取currentOption 1/2/3分别前插到[1]/[2]/[3]之前得到[1,1] [1,2] [1,3] [2,1] [2,2] [2,3] [3,1] [3,2] [3,3]共3^2 9个。值得注意的是这里每一层都会对smallerPermutations做全量重建ArrayList.addAll存在元素拷贝开销这部分成本我们在后文“复杂度分析”一节统一量化。四、无重复排列permutationWithoutRepetitions1. 完整实现public static ListListInteger permutationWithoutRepetitions(int[] permutationOptions) { if (permutationOptions.length 1) { ListListInteger result new ArrayList(); result.add(List.of(permutationOptions[0])); return result; } ListListInteger permutations new ArrayList(); int[] smallerOptions new int[permutationOptions.length - 1]; System.arraycopy(permutationOptions, 1, smallerOptions, 0, smallerOptions.length); ListListInteger smallerPermutations permutationWithoutRepetitions(smallerOptions); int firstOption permutationOptions[0]; for (ListInteger smallerPermutation : smallerPermutations) { for (int positionIndex 0; positionIndex smallerPermutation.size(); positionIndex) { ListInteger permutationPrefix new ArrayList(smallerPermutation.subList(0, positionIndex)); ListInteger permutationSuffix new ArrayList(smallerPermutation.subList(positionIndex, smallerPermutation.size())); ListInteger permutation new ArrayList(permutationPrefix); permutation.add(firstOption); permutation.addAll(permutationSuffix); permutations.add(permutation); } } return permutations; }2. 参数与递归逻辑拆解permutationOptions待全排列的元素数组无重复约束下排列长度固定为数组长度因此不需要permutationLength参数。算法的思路是经典的“固定首元素 插入法”递归出口当数组只剩 1 个元素时直接返回仅包含该元素的列表拆分首元素取出permutationOptions[0]剩余部分通过System.arraycopy拷贝为smallerOptions递归求解剩余部分对smallerOptions递归调用自身得到所有n-1个元素的全排列逐位置插入对每一个小排列依次把首元素插入到下标0 ~ size含末尾的每个可能位置即构造n种新排列。因为每个元素只会使用一次最终生成的结果数量恰为n!。3. 递归过程示例{1, 2, 3}对{3}递归返回[3]对{2, 3}首元素2插入[3]的 0、1 两个位置得到[2,3]、[3,2]对{1, 2, 3}首元素1分别插入[2,3]的 0、1、2 位置和[3,2]的 0、1、2 位置得到 6 个全排列[1,2,3] [2,1,3] [2,3,1] [1,3,2] [3,1,2] [3,2,1]。这里通过subList加两次拷贝的方式完成“在指定位置插入元素”实现上避免了手写循环移动数组逻辑也更贴近“插入”的语义。五、测试验证与运行结果原文档给出了两个对应的 JUnit 测试用例均在{1, 2, 3}上运行Test public void test_permutationWithRepetitions() { int[] permutationOptions {1, 2, 3}; ListListInteger permutation Permutations.permutationWithRepetitions(permutationOptions, 2); for (ListInteger list : permutation) { System.out.println(JSON.toJSONString(list)); } } Test public void test_permutationWithoutRepetitions() { int[] permutationOptions {1, 2, 3}; ListListInteger permutation Permutations.permutationWithoutRepetitions(permutationOptions); for (ListInteger list : permutation) { System.out.println(JSON.toJSONString(list)); } }有重复排列测试结果n 3, r 2共 9 个[1,1] [1,2] [1,3] [2,1] [2,2] [2,3] [3,1] [3,2] [3,3] Process finished with exit code 0输出恰好包含[1,1]、[2,2]、[3,3]这类重复使用元素的组合验证了“可重复”语义且数量9 3^2与公式一致。对于无重复测试根据第四节推导的递归过程{1, 2, 3}的输出应为 6 个全排列n! 6这与高中数学中的全排列结论相互印证仓库中该系列算法的完整工程代码位于作者开源的java-algorithms项目Permutations类感兴趣的读者可以结合 组合算法文档 中的Combinations类对比阅读。六、与组合、笛卡尔积、幂集的关联区分排列并非孤立的算法它是 CodeGuide 仓库algorithm/logic/sets系列“集合运算算法家族”的一员。下表对几个极易混淆的概念做一次集中辨析算法是否讲究顺序元素是否可重复结果数量仓库文档排列有重复讲究可重复n^r本文排列无重复讲究不可重复n!本文组合有/无重复不讲究视场景C(nr-1, r)/C(n, r)组合算法笛卡尔积讲究有序对跨集合组合|A| × |B|笛卡尔积幂集不讲究不可重复2^n幂集洗牌随机排列讲究不可重复n!中的随机一个Fisher-Yates 洗牌关键区分点在于排列 vs 组合排列中(A, B)与(B, A)是两种结果顺序有意义组合中二者等价。双色球选号属于组合而“三人排队站法”属于排列。组合的实现通过subList从i开始取剩余元素来天然避免顺序重复与排列的“逐位置插入”形成鲜明对比排列 vs 笛卡尔积有重复排列本质上是“同一个集合与自身的 r 次笛卡尔积”的枚举扑克牌13 × 4 52则是两个不同集合笛卡尔积的经典案例详见 笛卡尔积文档排列 vs 幂集幂集枚举的是“所有子集”2^n不关心元素顺序可视为比排列更低维度的问题详见 幂集文档。理解了这张“家族图谱”遇到具体业务问题时就能快速定位该用哪种算法。七、复杂度分析与工程实践建议1. 时间复杂度从源码结构看两份实现均为“先生成全部结果、一次性返回”的递归枚举有重复排列结果总量为n^r每构造一个长度为r的结果都需要O(r)的addAll拷贝因此总时间复杂度为O(r · n^r)无重复排列结果总量为n!每个结果的长度为n构造时同样伴随O(n)级拷贝因此总时间复杂度为O(n · n!)空间复杂度两者都因“全量收集到 List 后返回”而需要O(n^r)/O(n!)级的存储空间外加递归栈深度O(r)/O(n)。这也是排列类算法最需要警惕的一点结果数量是指数级乃至阶乘级爆炸的。例如n 10时无重复排列已达3,628,800个n 12时超过4.7 亿个内存很快就会被耗尽。2. 工程实践建议小规模枚举当n ≤ 8左右时本文的全量返回实现简单直接、易于测试适合在单元测试中生成全部排列用例大规模处理若n较大应改为“生成一个、消费一个”的迭代器/回调模式避免一次性持有全部结果递归写法也建议改为基于数组原地交换swap的经典回溯写法把空间开销降为O(n)典型应用场景多维度组合的测试数据生成、密码字典的全排列枚举、商品规格 SKU 的组合爆炸排查、以及线上试卷题目与选项乱序后者可直接使用 Fisher-Yates 洗牌算法仅需从n!种排列中随机取一个而无需全部枚举。八、小结排列算法看似只是两条高中数学公式的代码化但其背后包含了递归降维、首元素插入、结果全量枚举与复杂度爆炸等多个值得反复咀嚼的程序员思维点。本文完整覆盖了 原文档 中的两套 Java 实现、参数说明、测试用例与输出结果并补充了与阶乘、组合、笛卡尔积、幂集等仓库同系列算法的对照关系以及时间/空间复杂度的定量分析。掌握它你就掌握了“从数学公式到可运行代码”的完整闭环也为后续学习回溯算法、状态空间搜索等更复杂的枚举类问题打下了基础。【免费下载链接】CodeGuide:books: 本代码库是作者小傅哥多年从事一线互联网 Java 开发的学习历程技术汇总旨在为大家提供一个清晰详细的学习教程侧重点更倾向编写Java核心内容。如果本仓库能为您提供帮助请给予支持(关注、点赞、分享)项目地址: https://gitcode.com/gh_mirrors/code/CodeGuide创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

微信机器人为什么需要人工修改反馈:AI 被改过的回复其实是最有价值的训练数据

微信机器人为什么需要人工修改反馈:AI 被改过的回复其实是最有价值的训练数据

官网友情链接 wechatapi.net AI 微信机器人上线以后,很多团队会记录: 客户问了什么; AI 回了什么。 但还有一类数据,经常被忽略: 人工把 AI 的回复改成了什么。 例如 AI 建议回复: “该问题可以重新登…

2026/9/23 20:43:01 阅读更多 →
P7发布会技术栈搭建一文搞懂避坑指南

P7发布会技术栈搭建一文搞懂避坑指南

P7发布会技术栈搭建一文搞懂避坑指南 配置环境就卡半天,依赖冲突、版本不对、路径报错,这是无数开发者在P7级别项目初期的噩梦。很多新人以为P7发布会只是个大前端展示,其实背后是前后端分离、实时数据推送、高并发处理的综合实战。想 一文搞懂…

2026/9/23 20:43:01 阅读更多 →
LAVIS 中 Img2LLM-VQA 实战指南:用冻结大语言模型实现零样本视觉问答

LAVIS 中 Img2LLM-VQA 实战指南:用冻结大语言模型实现零样本视觉问答

LAVIS 中 Img2LLM-VQA 实战指南:用冻结大语言模型实现零样本视觉问答 【免费下载链接】LAVIS LAVIS - A One-stop Library for Language-Vision Intelligence 项目地址: https://gitcode.com/gh_mirrors/la/LAVIS 本指南围绕 LAVIS 官方仓库中的 projects/im…

2026/9/23 20:42:00 阅读更多 →

最新新闻

在 EOSIO 中使用 `cleos wallet import` 导入密钥对:完整操作指南与源码原理剖析

在 EOSIO 中使用 `cleos wallet import` 导入密钥对:完整操作指南与源码原理剖析

区块链 【免费下载链接】eos An open source smart contract platform 项目地址: https://gitcode.com/gh_mirrors/eo/eos 点击查看 免费下载 本篇指南聚焦 EOSIO 智能合约平台(当前仓库 eo/eos)中最常用的密钥管理操作——使用 cleos wall…

2026/9/23 21:28:23 阅读更多 →
GAN行人重识别:用特征空间对齐提升跨摄像头匹配精度

GAN行人重识别:用特征空间对齐提升跨摄像头匹配精度

简介:本资源是一套完整的基于生成对抗网络(GAN)的行人重识别毕业设计实现方案,面向深度学习初学者与计算机视觉方向本科生,聚焦跨摄像头场景下的身份匹配问题,适用于课程设计、毕设开发与算法复现学习。压缩…

2026/9/23 21:28:23 阅读更多 →
Akka Streams StreamConverters.asJavaStream 详解:将 Akka Sink 物化为 Java 8 Stream 的桥接之道

Akka Streams StreamConverters.asJavaStream 详解:将 Akka Sink 物化为 Java 8 Stream 的桥接之道

后端并发编程异步编程 【免费下载链接】akka-core A platform to build and run apps that are elastic, agile, and resilient. SDK, libraries, and hosted environments. 项目地址: https://gitcode.com/gh_mirrors/ak/akka-core 点击查看 免费下载 Akka Stream…

2026/9/23 21:28:23 阅读更多 →
【有源码】基于Hadoop+Spark的红白葡萄酒品质数据可视化分析平台-基于机器学习与数据挖掘的葡萄酒品质分析与可视化系统

【有源码】基于Hadoop+Spark的红白葡萄酒品质数据可视化分析平台-基于机器学习与数据挖掘的葡萄酒品质分析与可视化系统

注意:该项目只展示部分功能,如需了解,文末咨询即可。 本文目录1 开发环境2 系统设计3 系统展示3.1 大屏页面3.2 分析页面3.3 基础页面4 更多推荐5 部分功能代码1 开发环境 发语言:python 采用技术:Spark、Hadoop、Dja…

2026/9/23 21:28:23 阅读更多 →
基于Python的人脸识别系统毕设源码详解:从环境搭建到算法调优

基于Python的人脸识别系统毕设源码详解:从环境搭建到算法调优

简介:面向本科毕业设计及课程设计场景的人脸识别系统项目,基于Python实现,提供完整可运行的源码、毕业论文文档及配套说明。代码内含详细注释,结构清晰,新手也能快速理解关键逻辑;作者自述为98分高分项目&a…

2026/9/23 21:28:23 阅读更多 →
okbiye AI答辩PPT:功能与作用全解析

okbiye AI答辩PPT:功能与作用全解析

答辩是毕设的最后一道关,很多同学论文写得很好,却栽在了答辩PPT上:答辩前才开始做PPT,一页一页做了一周还是做不好,内容不知道怎么提炼,排版不专业,配色辣眼睛;讲稿写不好&#xff0…

2026/9/23 21:27:23 阅读更多 →

日新闻

3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A…

2026/9/23 0:00:23 阅读更多 →
2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我

2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我

2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我 刚把开发环境的显示器从1080P换到2K,跑老项目直接报错,版本升级后 API…

2026/9/23 0:01:25 阅读更多 →
3步搞定美眉图实战项目,告别官方文档抓不住重点

3步搞定美眉图实战项目,告别官方文档抓不住重点

3步搞定美眉图实战项目,告别官方文档抓不住重点 官方文档翻了三遍还是云里雾里?别急,美眉图在实战项目中常被用来做数据可视化,但它的原理比你想的简单。今天咱们直接上手,用一个完整的小项目把美眉图跑通,不再死磕那些冗长的理论说明。…

2026/9/23 0:01:25 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/23 4:55:02 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/23 4:49:06 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/23 9:53:41 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/23 9:53:40 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/23 9:53:40 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/23 9:53:40 阅读更多 →