Want Help Cracking FAANG?

(Then click this)

×
Back to Question Bank

254. Factor Combinations - Leetcode Solution

Code Implementation

class Solution:
    def getFactors(self, n: int):
        res = []
        def backtrack(start, target, path):
            for i in range(start, int(target ** 0.5) + 1):
                if target % i == 0:
                    res.append(path + [i, target // i])
                    backtrack(i, target // i, path + [i])
        backtrack(2, n, [])
        return res
      
class Solution {
public:
    vector<vector<int>> getFactors(int n) {
        vector<vector<int>> res;
        vector<int> path;
        backtrack(2, n, path, res);
        return res;
    }
    void backtrack(int start, int target, vector<int>& path, vector<vector<int>>& res) {
        for (int i = start; i * i <= target; ++i) {
            if (target % i == 0) {
                vector<int> temp = path;
                temp.push_back(i);
                temp.push_back(target / i);
                res.push_back(temp);
                path.push_back(i);
                backtrack(i, target / i, path, res);
                path.pop_back();
            }
        }
    }
};
      
class Solution {
    public List<List<Integer>> getFactors(int n) {
        List<List<Integer>> res = new ArrayList<>();
        backtrack(2, n, new ArrayList<>(), res);
        return res;
    }
    private void backtrack(int start, int target, List<Integer> path, List<List<Integer>> res) {
        for (int i = start; i * i <= target; ++i) {
            if (target % i == 0) {
                List<Integer> temp = new ArrayList<>(path);
                temp.add(i);
                temp.add(target / i);
                res.add(temp);
                path.add(i);
                backtrack(i, target / i, path, res);
                path.remove(path.size() - 1);
            }
        }
    }
}
      
var getFactors = function(n) {
    const res = [];
    function backtrack(start, target, path) {
        for (let i = start; i * i <= target; i++) {
            if (target % i === 0) {
                res.push([...path, i, target / i]);
                backtrack(i, target / i, [...path, i]);
            }
        }
    }
    backtrack(2, n, []);
    return res;
};
      

Problem Description

Given an integer n greater than 1, return all possible combinations of its factors (excluding 1 and n itself) such that the product of the numbers in each combination is n. Each combination should be a list of integers greater than 1, sorted in ascending order. Do not include duplicate combinations or reorderings. Each factor may be used multiple times in a combination, but the order of factors in a combination must be non-decreasing.

  • Input: an integer n (>1)
  • Output: a list of lists, each inner list is a valid factor combination for n
  • Do not use 1 or n itself as factors in the combinations
  • No duplicate combinations (e.g. [2, 6] and [6, 2] are considered the same, only one should appear)
  • Each factor in a combination must be in ascending order

Thought Process

At first glance, the problem looks similar to classic "combination sum" or "subset" problems, but with a twist: instead of summing to a target, we need to multiply to reach n. The simplest brute-force solution would be to try every possible combination of numbers between 2 and n-1 and check if their product equals n. However, this would be extremely inefficient, especially for large n.

To optimize, we notice that:

  • We only need to consider factors of n (i.e., numbers that divide n evenly).
  • Since order doesn't matter and combinations must be in ascending order, we can avoid duplicate work by always choosing factors greater than or equal to the previous one.
  • Recursion (backtracking) is a natural fit: at each step, try all valid factors starting from the current minimum, and recursively factor the quotient.
This leads us to a backtracking approach where we build up combinations incrementally, pruning the search space whenever the product exceeds or cannot divide n.

Solution Approach

We use a recursive backtracking algorithm to generate all valid factor combinations for n. Here's how it works step-by-step:

  1. Start with the smallest factor: For each call, we look for factors starting from 2 up to the square root of the current target number.
  2. Check divisibility: If the current number i divides target evenly, we know i is a valid factor.
  3. Build a combination: Add i and target / i to the current combination, and record it as a valid result.
  4. Recurse for further factorization: Recursively try to factor target / i, starting from i (to maintain ascending order), and add i to the combination path.
  5. Backtrack: Remove the last factor and continue trying the next possible factor.
  6. Termination: The recursion stops when target becomes 1 or no further factors can be found (i.e., when i * i > target).

This approach ensures that:

  • All combinations are unique and in ascending order
  • We only explore valid factor paths, skipping unnecessary work
  • We avoid using 1 or n itself as factors

Example Walkthrough

Let's use n = 12 as an example and trace the process:

  • Start with backtrack(2, 12, [])
  • Try i = 2: 12 % 2 == 0 ⇒ 2 is a factor. Add [2, 6] to results.
  • Recurse: backtrack(2, 6, [2])
    • Try i = 2: 6 % 2 == 0 ⇒ 2 is a factor. Add [2, 2, 3] to results.
    • Recurse: backtrack(2, 3, [2, 2])
      • 3 is only divisible by 3, which leads to 1, but we don't use 1 or n itself.
    • Try i = 3: 6 % 3 == 0 ⇒ 3 is a factor. Add [2, 3, 2] but since we always keep order, only [2, 2, 3] is added.
  • Try i = 3: 12 % 3 == 0 ⇒ 3 is a factor. Add [3, 4] to results.
  • Recurse: backtrack(3, 4, [3])
    • 4 % 3 != 0, so nothing is added.
  • Try i = 4: 12 % 4 == 0 ⇒ 4 is a factor. Add [4, 3], but again, only [3, 4] is kept due to order.

Final result: [[2, 6], [2, 2, 3], [3, 4]]

Time and Space Complexity

  • Brute-force approach:
    • Would try all combinations of numbers between 2 and n-1, leading to exponential time complexity: O(2n).
  • Optimized backtracking approach:
    • The number of unique factor combinations for a number n is related to the number of its divisors, which is much smaller than 2n.
    • For each call, we check up to sqrt(n) possible factors; recursion depth is at most log n (since each factorization reduces the target).
    • Time Complexity: O(k), where k is the total number of valid combinations (which is not polynomially bounded but much smaller than brute-force).
    • Space Complexity: O(log n) for recursion stack, plus O(k * m) for storing k combinations of up to m factors.

Summary

To solve the Factor Combinations problem, we use a recursive backtracking approach that systematically explores all unique ways to factor n into integers greater than 1, ensuring combinations are in ascending order and avoiding duplicates. By only considering valid factors at each step and recursing on the quotient, we efficiently generate all solutions without redundant work. This method is both elegant and practical, leveraging mathematical properties of factors and the power of recursion to solve the problem effectively.