zoukankan      html  css  js  c++  java
  • [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
  • 相关阅读:
    CSS实现返回网页顶部
    jQuery实现小火箭动态返回顶部代码
    Linux目录结构介绍
    Linux常用命令及技巧
    Linux文件系统
    Linux特性
    numpy中基础函数
    restful规范
    堆栈
    三次握手与四次挥手
  • 原文地址:https://www.cnblogs.com/lz87/p/7494025.html
Copyright © 2011-2022 走看看