马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
LeetCode第254题:因子的组合
题目描述
整数可以被看作是其因子的乘积。
比方:
- 8 = 2 × 4
- 8 = 2 × 2 × 2
- 12 = 2 × 6
- 12 = 2 × 2 × 3
- 12 = 3 × 4
请实现一个函数,该函数接收一个整数 n 并返回该整数全部的因子组合。
注意:
- 你可以假设 n 为正整数。
- 因子必须大于 1 且小于 n。
- 结果中不必包含 n 本身。
- 结果中的每个组合中的因子必须是非降序的。
- 结果中不能包含重复的组合。
难度
中等
题目链接
点击在LeetCode中检察题目
示例
示例 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]
- ]
复制代码 提示
解题思路
方法:回溯法 + 剪枝
我们可以使用回溯法来生成全部大概的因子组合。回溯法是一种通过实验不同的选择,然后在发现当前选择不满意条件时回退的算法。
关键点
- 使用回溯法遍历全部大概的因子组合
- 为了制止重复组合,我们在选择下一个因子时,只思量大于或即是当前因子的数
- 剪枝:不必思量大于剩余数值的平方根的因子,如许可以淘汰不须要的搜索
- 每次找到一个有用的因子,就将剩余的数除以这个因子,然后递归地寻找剩余数的因子
具体步骤
- 从最小的因子 2 开始,实验将 n 分解为当前因子和剩余数的乘积
- 假如当前因子能整除 n,则将其加入当前组合,并递归地寻找剩余数的因子
- 递归结束后,回溯到上一步,实验下一个大概的因子
- 为了制止重复,我们只思量大于或即是当前因子的数
- 为了剪枝,我们只思量小于或即是剩余数平方根的因子
复杂度分析
- 时间复杂度:O(2^(log n)),其中 log n 是 n 的因子数量的上限。对于每个大概的因子,我们都有选择或不选择两种大概,总共有 log n 个大概的因子。
- 空间复杂度:O(log n),递归栈的深度最多为 log n。
图解思路
回溯过程示例表(n = 12)
步骤当前组合当前因子剩余数操作结果1[]212选择因子 2[2]2[2]26选择因子 2[2, 2]3[2, 2]23选择因子 3[2, 2, 3]4[2, 2, 3]-1添加到结果结果:[[2, 2, 3]]5[2, 2]33不选择因子 3(已达到平方根限制)[2, 2]6[2]36选择因子 3[2, 3]7[2, 3]-2不满意条件(2 不能再被分解)[2, 3]8[2]66选择因子 6[2, 6]9[2, 6]-1添加到结果结果:[[2, 2, 3], [2, 6]]10[]312选择因子 3[3]11[3]44选择因子 4[3, 4]12[3, 4]-1添加到结果结果:[[2, 2, 3], [2, 6], [3, 4]] 剪枝计谋分析表
剩余数大概的因子范围剪枝后的因子范围说明122-112-3√12 ≈ 3.46,只需思量 ≤ 3 的因子62-52-2√6 ≈ 2.45,只需思量 ≤ 2 的因子42-32-2√4 = 2,只需思量 ≤ 2 的因子32-2-√3 ≈ 1.73,没有符合条件的因子2--2 是质数,没有更小的因子 代码实现
C# 实现
- public class Solution {
- public IList<IList<int>> GetFactors(int n) {
- IList<IList<int>> result = new List<IList<int>>();
- if (n <= 1) return result;
-
- // 回溯法寻找所有因子组合
- BackTrack(n, 2, new List<int>(), result);
-
- return result;
- }
-
- private void BackTrack(int n, int start, List<int> current, IList<IList<int>> result) {
- // 找到一个有效组合
- if (n == 1 && current.Count > 1) {
- result.Add(new List<int>(current));
- return;
- }
-
- // 尝试所有可能的因子
- for (int i = start; i <= Math.Sqrt(n); i++) {
- if (n % i == 0) {
- current.Add(i);
-
- // 递归寻找剩余数的因子,从当前因子开始,确保非降序
- BackTrack(n / i, i, current, result);
-
- // 回溯,尝试下一个因子
- current.RemoveAt(current.Count - 1);
- }
- }
-
- // 考虑将n本身作为一个因子(仅当当前组合不为空时)
- if (n > 1 && current.Count > 0) {
- current.Add(n);
- result.Add(new List<int>(current));
- current.RemoveAt(current.Count - 1);
- }
- }
- }
复制代码 Python 实现
- class Solution:
- def getFactors(self, n: int) -> List[List[int]]:
- result = []
- if n <= 1:
- return result
-
- # 回溯法寻找所有因子组合
- def backtrack(n, start, current):
- # 找到一个有效组合
- if n == 1 and len(current) > 1:
- result.append(current[:])
- return
-
- # 尝试所有可能的因子
- for i in range(start, int(n**0.5) + 1):
- if n % i == 0:
- current.append(i)
-
- # 递归寻找剩余数的因子,从当前因子开始,确保非降序
- backtrack(n // i, i, current)
-
- # 回溯,尝试下一个因子
- current.pop()
-
- # 考虑将n本身作为一个因子(仅当当前组合不为空时)
- if n > 1 and current:
- current.append(n)
- result.append(current[:])
- current.pop()
-
- backtrack(n, 2, [])
- return result
复制代码 C++ 实现
- class Solution {
- public:
- vector<vector<int>> getFactors(int n) {
- vector<vector<int>> result;
- if (n <= 1) return result;
-
- vector<int> current;
- backtrack(n, 2, current, result);
-
- return result;
- }
-
- private:
- void backtrack(int n, int start, vector<int>& current, vector<vector<int>>& result) {
- // 找到一个有效组合
- if (n == 1 && current.size() > 1) {
- result.push_back(current);
- return;
- }
-
- // 尝试所有可能的因子
- for (int i = start; i <= sqrt(n); i++) {
- if (n % i == 0) {
- current.push_back(i);
-
- // 递归寻找剩余数的因子,从当前因子开始,确保非降序
- backtrack(n / i, i, current, result);
-
- // 回溯,尝试下一个因子
- current.pop_back();
- }
- }
-
- // 考虑将n本身作为一个因子(仅当当前组合不为空时)
- if (n > 1 && !current.empty()) {
- current.push_back(n);
- result.push_back(current);
- current.pop_back();
- }
- }
- };
复制代码 执行结果
C# 实现
Python 实现
C++ 实现
性能对比
语言执行用时内存斲丧特点C#148 ms43.8 MB代码结构清晰,但性能较低Python44 ms15.9 MB语法简便,性能适中C++4 ms7.2 MB性能最佳,内存占用最小 代码亮点
|