[LeetCode] 254. Factor Combinations 因子組合


 

Numbers can be regarded as product of its factors. For example,

8 = 2 x 2 x 2;
  = 2 x 4.

Write a function that takes an integer n and return all possible combinations of its factors.

Note:

  1. You may assume that n is always positive.
  2. Factors should be greater than 1 and less than n.

Example 1:

Input: 1
Output: []

Example 2:

Input: 37
Output:[]

Example 3:

Input: 12
Output:
[
  [2, 6],
  [2, 2, 3],
  [3, 4]
]

Example 4:

Input: 32
Output:
[
  [2, 16],
  [2, 2, 8],
  [2, 2, 2, 4],
  [2, 2, 2, 2, 2],
  [2, 4, 4],
  [4, 8]
]

 

這道題給了我們一個正整數n,讓寫出所有的因子相乘的形式,而且規定了因子從小到大的順序排列,那么對於這種需要列出所有的情況的題目,通常都是用回溯法來求解的,由於題目中說明了1和n本身不能算其因子,那么可以從2開始遍歷到n,如果當前的數i可以被n整除,說明i是n的一個因子,將其存入一位數組 out 中,然后遞歸調用 n/i,此時不從2開始遍歷,而是從i遍歷到 n/i,停止的條件是當n等於1時,如果此時 out 中有因子,將這個組合存入結果 res 中,參見代碼如下:

 

解法一:

class Solution {
public:
    vector<vector<int>> getFactors(int n) {
        vector<vector<int>> res;
        helper(n, 2, {}, res);
        return res;
    }
    void helper(int n, int start, vector<int> out, vector<vector<int>>& res) {
        if (n == 1) {
            if (out.size() > 1) res.push_back(out);
            return;
        }
        for (int i = start; i <= n; ++i) {
            if (n % i != 0) continue;
            out.push_back(i);
            helper(n / i, i, out, res);
            out.pop_back();
        }
    }
};

 

下面這種方法用了個小 trick,我們仔細觀察題目中給的兩個例子的結果,可以發現每個組合的第一個數字都沒有超過n的平方根,這個也很好理解,由於要求序列是從小到大排列的,那么如果第一個數字大於了n的平方根,而且n本身又不算因子,那么后面那個因子也必然要與n的平方根,這樣乘起來就必然會超過n,所以不會出現這種情況。那么剛開始在2到n的平方根之間進行遍歷,如果遇到因子,先復制原來的一位數組 out 為一個新的一位數組 new_out,然后把此因子i加入 new_out,然后再遞歸調用 n/i,並且從i遍歷到 n/i 的平方根,之后再把 n/i 放入 new_out,並且存入結果 res,由於層層迭代的調用,凡是本身能繼續拆分成更小因數的都能在之后的迭代中拆分出來,並且加上之前結果,最終都會存 res 中,參見代碼如下:

 

解法二:

class Solution {
public:
    vector<vector<int>> getFactors(int n) {
        vector<vector<int>> res;
        helper(n, 2, {}, res);
        return res;
    }
    void helper(int n, int start, vector<int> out, vector<vector<int>> &res) {
        for (int i = start; i <= sqrt(n); ++i) {
            if (n % i != 0) continue;
            vector<int> new_out = out;
            new_out.push_back(i);
            helper(n / i, i, new_out, res);
            new_out.push_back(n / i);
            res.push_back(new_out);
        }
    }
};

 

上面兩種解法雖有些小不同,但是構成結果的順序都是相同,對於題目中給的兩個例子 n = 12 和 n = 32,結果如下:

 

n = 12
2 2 3
2 6
3 4

n = 32
2 2 2 2 2
2 2 2 4
2 2 8
2 4 4
2 16
4 8

 

上面兩種方法得到的結果跟題目中給的答案的順序不同,雖然順序不同,但是並不影響其通過 OJ。下面就給出生成題目中的順序的解法,這種方法也不難理解,還是從2遍歷到n的平方根,如果i是因子,那么遞歸調用n/i,結果用v來保存,然后新建一個包含i和 n/i 兩個因子的序列 out,然后將其存入結果 res, 然后再遍歷之前遞歸 n/i 的所得到的序列,如果i小於等於某個序列的第一個數字,那么將其插入該序列的首位置,然后將序列存入結果 res 中,舉個例子,比 n = 12,那么剛開始 i = 2,是因子,然后對6調用遞歸,得到 {2, 3},然后此時將 {2, 6} 先存入結果中,然后發現i(此時為2)小於等於 {2, 3} 中的第一個數字2,那么將2插入首位置得到 {2, 2, 3} 加入結果,然后此時i變成3,還是因子,對4調用遞歸,得到 {2, 2},此時先把 {3, 4} 存入結果,然后發現i(此時為3)大於 {2, 2} 中的第一個數字2,不做任何處理直接返回,這樣就得到正確的結果了:

 

解法三:

class Solution {
public:
    vector<vector<int>> getFactors(int n) {
        vector<vector<int>> res;
        for (int i = 2; i * i <= n; ++i) {
            if (n % i != 0) continue;
            vector<vector<int>> v = getFactors(n / i);
            vector<int> out{i, n / i};
            res.push_back(out);
            for (auto a : v) {
                if (i <= a[0]) {
                    a.insert(a.begin(), i);
                    res.push_back(a);
                }
            }
        }
        return res;
    }
};

 

這種方法對於對於題目中給的兩個例子 n = 12 和 n = 32,結果和題目中給的相同:

 

n = 12
2 6
2 2 3
3 4

n = 32
2 16
2 2 8
2 2 2 4
2 2 2 2 2
2 4 4
4 8

 

Github 同步地址:

https://github.com/grandyang/leetcode/issues/254

 

類似題目:

Combination Sum III

Combination Sum II

Combination Sum

 

參考資料:

https://leetcode.com/problems/factor-combinations/

https://leetcode.com/problems/factor-combinations/discuss/68039/A-simple-java-solution

https://leetcode.com/problems/factor-combinations/discuss/68040/My-Recursive-DFS-Java-Solution

https://leetcode.com/problems/factor-combinations/discuss/68132/Share-simple-C%2B%2B-DFS-accepted-solution

 

LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM