Facebook Pixel

2521. Distinct Prime Factors of Product of Array

MediumArrayHash TableMathNumber Theory
Leetcode Link

Problem Description

You are given an array of positive integers nums. Your task is to find the number of distinct prime factors that appear in the product of all elements in the array.

A prime number is a number greater than 1 that can only be divided evenly by 1 and itself. For example, 2, 3, 5, 7, 11 are prime numbers.

A number val1 is a factor of another number val2 if val2 divided by val1 gives an integer result (no remainder).

The key insight is that you need to find all unique prime numbers that divide at least one element in the array. When you multiply all elements together to get the product, these prime factors will be part of the prime factorization of that product.

For example, if nums = [2, 4, 3, 7, 10, 6]:

  • The product is 2 × 4 × 3 × 7 × 10 × 6 = 10080
  • Breaking down each number into prime factors:
    • 2 = 2
    • 4 = 2²
    • 3 = 3
    • 7 = 7
    • 10 = 2 × 5
    • 6 = 2 × 3
  • The distinct prime factors are: 2, 3, 5, 7
  • So the answer is 4

The solution uses prime factorization for each number in the array and collects all unique prime factors using a set data structure. For each number, it finds all prime factors by trial division starting from 2, and adds them to the set. The final answer is the size of this set.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The key observation is that when we multiply all numbers in the array together, the prime factorization of the product will contain all prime factors from individual numbers. However, we don't actually need to compute this potentially huge product.

Think about it this way: if a prime number p divides any number in the array, then p will also divide the product of all numbers. For example, if 2 divides 10 in the array, then 2 will definitely divide the final product regardless of what other numbers are present.

This leads us to a simpler approach: instead of calculating the product first (which could cause overflow), we can find prime factors of each number individually and collect them. Since we only care about distinct prime factors, not their frequencies, we can use a set to automatically handle duplicates.

The process becomes:

  1. For each number in the array, find all its prime factors
  2. Add these prime factors to a set (which keeps only unique values)
  3. The size of the set gives us the count of distinct prime factors

For prime factorization itself, we use trial division: we try dividing by potential factors starting from 2. When we find a factor i, we keep dividing by i until it's no longer a factor (this handles prime powers like in 8). We only need to check factors up to √n because if n has a factor larger than √n, it can have at most one such factor, and that factor would be n itself after removing all smaller prime factors.

This approach is efficient because we avoid computing large products and instead work with each number independently, collecting unique prime factors as we go.

Learn more about Math patterns.

Solution Approach

The solution uses a hash table (set) combined with prime factorization to find all distinct prime factors across the array elements.

Data Structure Used:

  • A set to store unique prime factors found across all numbers

Algorithm Steps:

  1. Initialize an empty set s to store distinct prime factors.

  2. Iterate through each number n in the input array nums.

  3. For each number, perform prime factorization:

    • Start with the smallest prime candidate i = 2
    • While i <= n // i (equivalent to i <= √n):
      • Check if i is a factor of n by testing n % i == 0
      • If i is a factor:
        • Add i to the set (it's a prime factor)
        • Completely remove this prime factor by repeatedly dividing: while n % i == 0: n //= i
      • Increment i to check the next potential factor
  4. Handle remaining prime factor:

    • After the loop, if n > 1, then n itself is a prime factor
    • This happens when n has a prime factor greater than √n
    • Add this remaining n to the set
  5. Return the result: The size of the set len(s) gives the count of distinct prime factors.

Why this works:

  • The condition i <= n // i ensures we only check divisors up to √n, which is sufficient because any composite number must have at least one prime factor ≤ √n
  • The inner while loop while n % i == 0: n //= i removes all occurrences of prime i from n, effectively extracting the prime and reducing n
  • By dividing out each prime factor completely, we ensure that each i that divides n is actually prime (not composite)
  • Using a set automatically handles duplicates - if multiple numbers share the same prime factor, it's only counted once

Time Complexity: O(m × √k) where m is the length of the array and k is the maximum value in the array.

Space Complexity: O(p) where p is the number of distinct prime factors found.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through the solution with nums = [12, 15, 10].

Step 1: Initialize empty set

  • s = {}

Step 2: Process first number (12)

  • n = 12, start with i = 2
  • Check if 2 divides 12: Yes (12 % 2 == 0)
    • Add 2 to set: s = {2}
    • Remove all 2's: 12 ÷ 2 = 6, then 6 ÷ 2 = 3
    • Now n = 3
  • Increment to i = 3
  • Check condition 3 <= 3 // 3 (3 <= 1): False, exit loop
  • Check remaining: n = 3 > 1, so add 3 to set
  • After processing 12: s = {2, 3}

Step 3: Process second number (15)

  • n = 15, start with i = 2
  • Check if 2 divides 15: No (15 % 2 ≠ 0)
  • Increment to i = 3
  • Check if 3 divides 15: Yes (15 % 3 == 0)
    • Add 3 to set: s = {2, 3} (3 already exists, no change)
    • Remove all 3's: 15 ÷ 3 = 5
    • Now n = 5
  • Increment to i = 4
  • Check condition 4 <= 5 // 4 (4 <= 1): False, exit loop
  • Check remaining: n = 5 > 1, so add 5 to set
  • After processing 15: s = {2, 3, 5}

Step 4: Process third number (10)

  • n = 10, start with i = 2
  • Check if 2 divides 10: Yes (10 % 2 == 0)
    • Add 2 to set: s = {2, 3, 5} (2 already exists, no change)
    • Remove all 2's: 10 ÷ 2 = 5
    • Now n = 5
  • Increment to i = 3
  • Check condition 3 <= 5 // 3 (3 <= 1): False, exit loop
  • Check remaining: n = 5 > 1, so add 5 to set
  • After processing 10: s = {2, 3, 5} (5 already exists, no change)

Step 5: Return result

  • Final set: s = {2, 3, 5}
  • Return len(s) = 3

The answer is 3 distinct prime factors. We can verify: the product 12 × 15 × 10 = 1800 = 2³ × 3² × 5², which indeed has exactly three distinct prime factors: 2, 3, and 5.

Solution Implementation

1class Solution:
2    def distinctPrimeFactors(self, nums: List[int]) -> int:
3        # Set to store unique prime factors across all numbers
4        prime_factors = set()
5      
6        # Process each number in the input array
7        for num in nums:
8            # Start checking for prime factors from 2
9            divisor = 2
10          
11            # Check divisors up to sqrt(num) for efficiency
12            while divisor * divisor <= num:
13                # If divisor is a factor of num
14                if num % divisor == 0:
15                    # Add this prime factor to the set
16                    prime_factors.add(divisor)
17                  
18                    # Remove all occurrences of this prime factor from num
19                    while num % divisor == 0:
20                        num //= divisor
21              
22                # Move to next potential divisor
23                divisor += 1
24          
25            # If num > 1 after factorization, it's a prime factor itself
26            if num > 1:
27                prime_factors.add(num)
28      
29        # Return the count of distinct prime factors
30        return len(prime_factors)
31
1class Solution {
2    /**
3     * Returns the number of distinct prime factors across all elements in the array.
4     * @param nums - array of positive integers
5     * @return count of unique prime factors found in all array elements
6     */
7    public int distinctPrimeFactors(int[] nums) {
8        // Set to store unique prime factors across all numbers
9        Set<Integer> primeFactors = new HashSet<>();
10      
11        // Process each number in the array
12        for (int number : nums) {
13            // Find prime factors of current number
14            findPrimeFactors(number, primeFactors);
15        }
16      
17        // Return the count of distinct prime factors
18        return primeFactors.size();
19    }
20  
21    /**
22     * Helper method to find and add prime factors of a number to the set.
23     * @param number - the number to factorize
24     * @param primeFactors - set to store the prime factors
25     */
26    private void findPrimeFactors(int number, Set<Integer> primeFactors) {
27        // Check for prime factors from 2 up to sqrt(number)
28        for (int factor = 2; factor * factor <= number; factor++) {
29            // If factor divides the number, it's a prime factor
30            if (number % factor == 0) {
31                // Add the prime factor to the set
32                primeFactors.add(factor);
33              
34                // Remove all occurrences of this prime factor
35                while (number % factor == 0) {
36                    number /= factor;
37                }
38            }
39        }
40      
41        // If number > 1 after factorization, it's a prime factor itself
42        if (number > 1) {
43            primeFactors.add(number);
44        }
45    }
46}
47
1class Solution {
2public:
3    int distinctPrimeFactors(vector<int>& nums) {
4        // Set to store unique prime factors across all numbers
5        unordered_set<int> primeFactors;
6      
7        // Process each number in the input array
8        for (int& num : nums) {
9            // Find all prime factors of current number
10            // Only check divisors up to sqrt(num) for efficiency
11            for (int divisor = 2; divisor <= num / divisor; ++divisor) {
12                // Check if divisor is a factor of num
13                if (num % divisor == 0) {
14                    // Add this prime factor to the set
15                    primeFactors.insert(divisor);
16                  
17                    // Remove all occurrences of this prime factor from num
18                    while (num % divisor == 0) {
19                        num /= divisor;
20                    }
21                }
22            }
23          
24            // If num > 1 after factorization, it's a prime factor itself
25            // (This handles prime factors greater than sqrt(original num))
26            if (num > 1) {
27                primeFactors.insert(num);
28            }
29        }
30      
31        // Return the count of distinct prime factors
32        return primeFactors.size();
33    }
34};
35
1/**
2 * Counts the number of distinct prime factors across all numbers in the array
3 * @param nums - Array of positive integers
4 * @returns The count of distinct prime factors
5 */
6function distinctPrimeFactors(nums: number[]): number {
7    // Set to store unique prime factors
8    const primeFactors: Set<number> = new Set<number>();
9  
10    // Process each number in the array
11    for (let num of nums) {
12        let currentNumber = num;
13        let divisor = 2;
14      
15        // Check for prime factors up to sqrt(currentNumber)
16        while (divisor <= currentNumber / divisor) {
17            // If divisor is a factor of currentNumber
18            if (currentNumber % divisor === 0) {
19                // Add the prime factor to the set
20                primeFactors.add(divisor);
21              
22                // Remove all occurrences of this prime factor
23                while (currentNumber % divisor === 0) {
24                    currentNumber = Math.floor(currentNumber / divisor);
25                }
26            }
27            divisor++;
28        }
29      
30        // If currentNumber > 1, it's a prime factor itself
31        if (currentNumber > 1) {
32            primeFactors.add(currentNumber);
33        }
34    }
35  
36    // Return the count of distinct prime factors
37    return primeFactors.size;
38}
39

Time and Space Complexity

Time Complexity: O(n × √m)

The algorithm iterates through each of the n numbers in the array. For each number, it performs prime factorization using trial division. The key optimization is the condition i <= n // i (equivalent to i² <= n), which means we only check divisors up to √n. In the worst case, when factorizing the maximum value m in the array, we check up to √m potential divisors. Therefore, the overall time complexity is O(n × √m).

Space Complexity: O(m / log m)

The space is primarily used by the set s to store distinct prime factors. According to the Prime Number Theorem, the number of primes less than or equal to m is approximately m / ln(m). Since we're storing only the distinct prime factors from all numbers in the array, and these prime factors cannot exceed m, the maximum number of distinct primes we can store is bounded by O(m / log m).

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Not Handling Large Prime Factors Correctly

A critical pitfall occurs when forgetting to check if num > 1 after the factorization loop. This remaining value represents a prime factor larger than √num.

Incorrect Implementation:

for num in nums:
    divisor = 2
    while divisor * divisor <= num:
        if num % divisor == 0:
            prime_factors.add(divisor)
            while num % divisor == 0:
                num //= divisor
        divisor += 1
    # Missing: if num > 1: prime_factors.add(num)

Problem: This misses prime factors greater than √num. For example, with num = 14:

  • After dividing by 2, we get 7
  • Since 3² = 9 > 7, the loop ends
  • We never add 7 to our prime factors set

Solution: Always check and add the remaining value if it's greater than 1.

2. Inefficient Prime Checking with divisor++

Using divisor += 1 checks all numbers, including even numbers after 2, which wastes computation.

Inefficient Approach:

divisor = 2
while divisor * divisor <= num:
    # ... factorization logic ...
    divisor += 1  # Checks 2, 3, 4, 5, 6, 7, 8...

Optimized Solution:

divisor = 2
while divisor * divisor <= num:
    if num % divisor == 0:
        prime_factors.add(divisor)
        while num % divisor == 0:
            num //= divisor
  
    # Skip even numbers after 2
    if divisor == 2:
        divisor = 3
    else:
        divisor += 2  # Only check odd numbers: 3, 5, 7, 9...

3. Not Removing All Occurrences of a Prime Factor

Failing to completely divide out a prime factor can lead to treating composite numbers as primes.

Incorrect Implementation:

if num % divisor == 0:
    prime_factors.add(divisor)
    num //= divisor  # Only divides once!
    divisor += 1

Problem: For num = 12 (which is 2² × 3):

  • After dividing by 2 once, we get 6
  • We then check if 3 divides 6, but 6 still contains factor 2
  • This could lead to incorrect identification of prime factors

Solution: Use a while loop to completely remove each prime factor:

while num % divisor == 0:
    num //= divisor

4. Integer Overflow in Condition Check

Using divisor * divisor <= num can cause integer overflow for very large numbers in some languages.

Safer Alternative:

while divisor <= num // divisor:  # Mathematically equivalent but avoids overflow
    # ... factorization logic ...

This prevents potential overflow issues when divisor is large, though Python handles big integers naturally.

Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Consider the classic dynamic programming of longest increasing subsequence:

Find the length of the longest subsequence of a given sequence such that all elements of the subsequence are sorted in increasing order.

For example, the length of LIS for [50, 3, 10, 7, 40, 80] is 4 and LIS is [3, 7, 40, 80].

What is the recurrence relation?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More