题目链接:🔒LeetCode254:因子的组合
给定一个正整数 n
,返回所有可能的因子组合。因子必须满足:
- 大于 1 且小于
n
- 组合中的因子按非降序排列
- 结果中不包含
n
本身(例如n = n
无效) - 结果无重复组合
示例1:
输入: n = 1
输出: []
示例2:
输入: n = 12
输出:
[
[2, 6],
[2, 2, 3],
[3, 4]
]
示例3:
输入: n = 32
输出:
[
[2, 16],
[2, 2, 8],
[2, 2, 2, 4],
[2, 2, 2, 2, 2],
[2, 4, 4],
[4, 8]
]
解题思路
采用 回溯法 + 剪枝 优化:
-
回溯框架:
- 从起始因子
start
(初始为 2)开始遍历。 - 若当前因子
i
能整除n
,将其加入路径,递归分解n/i
。
- 从起始因子
-
关键剪枝:
- 因子范围:仅需遍历
i ≤ √n
,避免重复(如12
的因子3
和4
只需处理到√12≈3.46
)。 - 非降序保证:递归时起始因子设为
i
,确保后续因子不小于当前因子。
- 因子范围:仅需遍历
-
终止条件:
- 当
n = 1
且路径长度 > 1 时,保存有效组合。 - 循环结束后,若路径非空,将剩余值
n
加入路径(如[3, 4]
中的4
)。
- 当
代码实现(Java版)
class Solution {
public List<List<Integer>> getFactors(int n) {
List<List<Integer>> res = new ArrayList<>();
backtrack(n, 2, new ArrayList<>(), res);
return res;
}
private void backtrack(int n, int start, List<Integer> path, List<List<Integer>> res) {
// 遍历范围:start → √n
for (int i = start; i * i <= n; i++) {
if (n % i == 0) {
path.add(i); // 选择当前因子
backtrack(n / i, i, path, res); // 递归分解剩余值
path.remove(path.size() - 1); // 回溯
}
}
// 保存有效组合(避免 n 本身单独作为结果)
if (!path.isEmpty()) {
path.add(n);
res.add(new ArrayList<>(path));
path.remove(path.size() - 1);
}
}
}
代码说明
-
核心变量:
res
:结果集。path
:当前搜索路径,存储临时因子组合。start
:起始因子,确保因子非降序且去重。
-
剪枝优化:
- 循环条件:
i * i <= n
等价于i ≤ √n
,减少无效遍历(如n=12
时只需检查2, 3
)。 - 递归起点:
backtrack(n/i, i, ...)
保证后续因子≥ i
,避免重复组合(如[2,2,3]
有效,[2,3,2]
无效)。
- 循环条件:
-
终止处理:
- 循环结束后,若
path
非空,将剩余值n
加入路径(如12 → [3,4]
中的4
在递归退出后添加)。
- 循环结束后,若