[LintCode] Factorization

A non-negative numbers can be regarded as product of its factors.
Write a function that takes an integer n and return all possible combinations of its factors.

 Notice
  • Elements in a combination (a1, a2, … , ak) must be in non-descending order. (ie, a1 ≤ a2 ≤ … ≤ ak).
  • The solution set must not contain duplicate combination.
Example

Given n = 8
return [[2,2,2],[2,4]]
// 8 = 2 x 2 x 2 = 2 x 4.

Given n = 1
return []

Given n = 12
return [[2,6],[2,2,3],[3,4]]

 
By definition, factors should be greater than 1 and less than n itself, which means [1, n] is not a valid factorization of n. 
To avoid duplicated fatorization answers, for a given factorization, if we've already found some factors, all factors that are
yet to be found must be >= its previously found factor. 
 
Output condition: when n becomes 1 after dividing all the factors, we should add the current list as one of the factorization.
However, we also need to avoid adding the factorization of [n, 1]. Since we start the dfs from 2, we know that if the case of 
using n itself as a factor, there should be only 1 element in the current list. Thus, when n == 1, we check if the list size is > 1.
If it is, we have a valid factorization. 
 
Solution 1. 
 1 public class Solution {
 2     public List<List<Integer>> getFactors(int n) {
 3         List<List<Integer>> results = new ArrayList<List<Integer>>();
 4         getFactorsDfs(results, new ArrayList<Integer>(), n, 2);
 5         return results;
 6     }
 7     private void getFactorsDfs(List<List<Integer>> results, List<Integer> list, int n, int startFactor) {
 8         if(n == 1) {
 9             if(list.size() > 1) {
10                 results.add(new ArrayList<Integer>(list));
11             }
12             return;
13         }
14         for(int i = startFactor; i <= n; i++) {
15             if(n % i == 0) {
16                 list.add(i);
17                 getFactorsDfs(results, list, n / i, i);
18                 list.remove(list.size() - 1);
19             }
20         }
21     }
22 }

 

Solution 2. Efficient than solution 1. 

Solution 1 works correctly but does a lot of unnecessary work. If we uses the fact that any factorization that starts with a factor that is bigger than 

Math.sqrt(n) is going to be a duplicated answer, we can get a more efficient solution. 

Take n == 12 as an example, sqrt(12) is >= 3 but < 4. we have the following factorizations that start with a factor >= 4:

[4, 3]; [6, 2]; they are duplicates of [3, 4] and [2, 6] respectively. 

This is true because for n = a * b, a <= sqrt(n), b>= sqrt(n), if we start to check n's factor from small to big, then we will check case of a * b prior to case of b * a.

As a result, we can cut the stop condition from i <= n to i <= Math.sqrt(n) without losing any valid factorization.

 

However, this optimization comes with a cost. When the stop condition is i <= Math.sqrt(n), we eliminated all [n, 1] factorizations, not only for the original input n,

but also for n's factors. For example, if n == 12, then [12, 1] will not be considered. When we recursively calls getFactorsDfs on 12's factor 6, we also eliminated the 

factorization of [6,1] for 6 since i is in range [2, Math.sqrt(6)]; This causes the factorization of [2, 6] is missed. The reason is that we should only enfore the rule 

of "actors should be greater than 1 and less than n itself" on the original input n, not on any of its factors. 

To fix this, the highlighted code is added after [startFactor, sqrt(n)] are all checked. It checks if we can use the current n at the current recursive call level as a valid factor.

For the case of the original input n, the list only contains 1 element of n, so this list will not be added as a valid factorization.

For the case of n's factors f, the list already contains at least 2 elements(the divisor d that meets n % d == f and f itself), this list will be added as a valid factorization.

 

 1 public class Solution {
 2     public List<List<Integer>> getFactors(int n) {
 3         List<List<Integer>> results = new ArrayList<List<Integer>>();
 4         getFactorsDfs(results, new ArrayList<Integer>(), n, 2);
 5         return results;
 6     }
 7     private void getFactorsDfs(List<List<Integer>> results, List<Integer> list, int n, int startFactor) {
 8         if(n == 1) {
 9             if(list.size() > 1) {
10                 results.add(new ArrayList<Integer>(list));
11             }
12             return;
13         }
14         for(int i = startFactor; i <= Math.sqrt(n); i++) {
15             if(n % i == 0) {
16                 list.add(i);
17                 getFactorsDfs(results, list, n / i, i);
18                 list.remove(list.size() - 1);
19             }
20         }
21         if(n >= startFactor) {
22             list.add(n);
23             getFactorsDfs(results, list, 1, n);
24             list.remove(list.size() - 1);
25         }
26     }
27 }

 

 
Related Problems
Combination Sum
posted @ 2017-09-26 13:49  Review->Improve  阅读(551)  评论(0编辑  收藏  举报