Java数组实现全排列或子集的核心是回溯:全排列需排序+used数组+剪枝(跳过相同且前一未用元素),子集则每层选/不选、从start索引向后遍历避免重复。

Java 中用数组实现全排列或子集生成,核心是回溯(Backtracking)——通过递归+状态重置,在每层选择一个元素、深入、回退,避免重复或遗漏。
全排列(含重复元素去重)
对整型数组 nums 生成所有不重复的排列。关键点:排序 + 剪枝(跳过相同值且前一个未被使用的情况)。
- 先对数组排序,使相同元素相邻
- 用布尔数组
used标记某位置元素是否已选 - 递归中,若
nums[i] == nums[i-1]且!used[i-1],说明前一个相同数刚被撤销,当前这个跳过(否则会重复) - 路径长度等于数组长度时,保存当前排列(建议用
new ArrayList(path)拷贝)
子集生成(Subsets)
对无序数组生成所有子集(含空集),无需排序,也不需要 used 数组。每层决策:「选当前元素」或「不选」,对应两种分支。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 每次递归都把当前
path加入结果(子集不要求完整长度) - 从索引
start开始遍历,避免重复组合(如 [1,2] 和 [2,1] 视为同一子集) - 进入下一层时传入
i + 1,保证只向后选,不回头
通用回溯结构(数组适配版)
无论全排列还是子集,都遵循相似骨架:
立即学习“Java免费学习笔记(深入)”;
- 定义结果列表
List<List<Integer>> res和路径暂存List<Integer> path - 主方法中初始化,并调用回溯函数(传入起始索引或 used 数组等上下文)
- 回溯函数内:满足条件则添加结果;遍历可选项;做选择(add / used[i]=true);递归;撤销选择(remove / used[i]=false)
注意数组 vs 列表的细节
Java 数组本身不可变长,回溯中路径推荐用 ArrayList;若坚持用数组,需额外维护当前长度变量,手动拷贝更麻烦。输入是数组时,常转为 List 方便操作,或直接按索引访问原数组。输出结果一般为 List<List<Integer>>,不是二维数组——因为各子集/排列长度不同,二维数组难以统一维度。

















