【LeetCode(Java) - 254】因子的組合

學哥斌發表於2020-09-27

1、題目描述

在這裡插入圖片描述

2、解題思路

  題目要求因子的範圍是 [2, n-1]。

  先對 n 開平方根取整數得到 sqrtN,那麼,n 的因子中,一半因子小於等於 sqrtN,一半因子大於等於 sqrtN。

  於是我們只需要從 [2, sqrtN] 中找到一個因數 i,則另一個因數就是 n/i,即找到了一對因數。

  題意要返回所有的因子組合,於是我們可以對兩個因子進行遞迴拆分,最後合併。

  以 n == 16 為例:

  n 開平方根為 4,於是先從 [2, 4] 區間找因子,只要能整除 16,就是因子,於是找到了 2 和 4。

  當一個因子為 2 時,另一個因子為 16/2 = 8;

  當一個因子為 4 時,另一個因子為 16/4 = 4;

  於是找到了因子組合:{2,8}、{4,4}。

  每確定一個因子組合,都對第二個數字進行拆分,比如 {2,8} 需要對 8 進行拆分,8 的因子不能小於和它配對的 2。

  於是問題又變成:找數字 8 的區間在 [2, 7] 的因子,按照一樣的遞迴計算。

  8 的因子組合為 {4,2}、{2,2,2}。

  給 8 的因子組合都舔加一個它的搭檔,這裡是 2,就是 16 的因子組合了:

  {4,2,2}、{2,2,2,2}

  所以 16 的因子組合為:{2,8}、{2,4,2,2}、{2,2,2,2}

  對於 {4,4} 同理,對第二個 4 進行拆分,4 的因子不能小於和它配對的 4,發現沒有小於 4 的因數。

  綜合,16 的因子組合為 {2,8}、{2,4,2,2}、{2,2,2,2}、{4,4}

3、解題程式碼

class Solution {

    public List<List<Integer>> getFactors(int n) {
        return dfs(2, n);
    }

    /**
     * 大於等於 start 的 num 的因子組合
     * @param start
     * @param num
     * @return
     */
    public static List<List<Integer>> dfs(int start, int num) {
        if (num == 1) {
            return new ArrayList<>();
        }
        // C = A × B,則 A 和 B 一個小於等於根號 C,一個大於等於根號 C
        int qNum = (int) Math.sqrt(num);
        List<List<Integer>> result = new ArrayList<>();
        // 找出 [start, 根號num] 中,是 num 因子的數字
        for (int i = start; i <= qNum; i++) {
            if (num % i == 0) { // 找到一個因子
                List<Integer> simpleList = new ArrayList<>();
                simpleList.add(i);  // 小於或等於根號 num 的因子
                simpleList.add(num / i);    // 大於或等於根號 num 的因子
                result.add(simpleList); // 找到一對因子
                // 檢查大於等於根號 num 的因子能怎麼拆
                List<List<Integer>> nextLists = dfs(i, num / i);
                for (List<Integer> list : nextLists) {
                    list.add(i);    // list 的元素相乘是 num/i ,舔一個 i,相乘就是 num
                    result.add(list);
                }
            }
        }
        return result;
    }
}

相關文章