Facebook Pixel

1390. Four Divisors

Problem Description

You are given an integer array nums. Your task is to find all integers in the array that have exactly four divisors, and return the sum of all divisors for those integers.

A divisor of a number is any integer that divides the number evenly (with no remainder). For example, the divisors of 12 are 1, 2, 3, 4, 6, 12 (which is 6 divisors total, so it wouldn't qualify).

The key requirements are:

  • Check each integer in the array to see if it has exactly 4 divisors
  • If an integer has exactly 4 divisors, add up all its divisors
  • Return the total sum of all divisors from all qualifying integers
  • If no integer in the array has exactly 4 divisors, return 0

For example:

  • The number 21 has divisors 1, 3, 7, 21 (exactly 4 divisors), so we would add 1 + 3 + 7 + 21 = 32 to our answer
  • The number 8 has divisors 1, 2, 4, 8 (exactly 4 divisors), so we would add 1 + 2 + 4 + 8 = 15 to our answer
  • The number 6 has divisors 1, 2, 3, 6 (exactly 4 divisors), so we would add 1 + 2 + 3 + 6 = 12 to our answer

The solution works by iterating through each number in the array, finding all its divisors, and checking if the count equals 4. If it does, the sum of those divisors is added to the final result.

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

Intuition

The core insight is that we need to find all divisors of each number efficiently. When looking for divisors of a number x, we don't need to check every number from 1 to x. Instead, we can leverage a key mathematical property: divisors come in pairs.

For any divisor i of x, there's a corresponding divisor x/i. For example, if 12 is divisible by 3, then 12/3 = 4 is also a divisor. This means we only need to check numbers up to √x, because after that point, we'd be finding the same pairs in reverse order.

When we find a divisor i, we can immediately know that both i and x/i are divisors. This allows us to:

  1. Count 2 divisors at once (in most cases)
  2. Add both divisors to our sum simultaneously

There's one special case to handle: when i * i = x (perfect squares). In this case, i and x/i are the same number, so we should only count it once.

We start with a count of 2 and sum of x + 1 because every number has at least two divisors: 1 and itself. Then we iterate from 2 to √x to find any additional divisor pairs.

The efficiency comes from the fact that we're only iterating up to √x instead of x, which significantly reduces the number of operations for large numbers. Once we've found all divisors and counted them, we simply check if the count equals 4. If it does, we return the sum; otherwise, we return 0.

This approach is applied to each number in the array independently, and the final answer is the sum of all individual results.

Learn more about Math patterns.

Solution Approach

The solution implements a factor decomposition approach to find all divisors of each number in the array.

The main function iterates through each number in nums and applies a helper function f(x) that:

  1. Initializes counters and sum:

    • cnt = 2 (starting with 2 because every number has at least two divisors: 1 and itself)
    • s = x + 1 (sum starts with 1 + x)
    • i = 2 (start checking from 2)
  2. Iterates up to √x: The loop condition i <= x // i is equivalent to i <= √x, but avoids floating-point operations. This optimization reduces time complexity from O(n) to O(√n) for each number.

  3. Checks for divisibility: For each i, if x % i == 0, then i is a divisor:

    • Increment the count by 1 and add i to the sum
    • Check if i * i != x (not a perfect square case):
      • If true, we've found a pair of divisors: i and x // i
      • Increment count by 1 more and add x // i to the sum
    • This handles both divisors in a pair simultaneously
  4. Returns conditional result: After checking all potential divisors:

    • If cnt == 4, return the sum s (this number has exactly 4 divisors)
    • Otherwise, return 0 (doesn't meet the requirement)
  5. Aggregates results: The main function uses sum(f(x) for x in nums) to apply the helper function to each number and sum all the results.

The algorithm efficiently handles edge cases:

  • Perfect squares are correctly handled by the i * i != x check
  • Numbers with fewer or more than 4 divisors return 0
  • The integer division x // i ensures we work with integers throughout

Time complexity: O(n * √m) where n is the length of the array and m is the maximum value in the array. Space complexity: O(1) as we only use a constant amount of extra space.

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 = [21, 6, 8].

Processing first number: 21

  1. Initialize: cnt = 2, s = 21 + 1 = 22 (accounting for divisors 1 and 21)
  2. Check i = 2: 21 % 2 ≠ 0, not a divisor, continue
  3. Check i = 3: 21 % 3 = 0, so 3 is a divisor
    • Increment cnt to 3, add 3 to sum: s = 22 + 3 = 25
    • Since 3 * 3 ≠ 21, we also have divisor 21 // 3 = 7
    • Increment cnt to 4, add 7 to sum: s = 25 + 7 = 32
  4. Check i = 4: 4 * 4 = 16 < 21, so continue
    • 21 % 4 ≠ 0, not a divisor
  5. Stop at i = 5 since 5 * 5 = 25 > 21
  6. Final: cnt = 4, so return sum of 32

Processing second number: 6

  1. Initialize: cnt = 2, s = 6 + 1 = 7 (divisors 1 and 6)
  2. Check i = 2: 6 % 2 = 0, so 2 is a divisor
    • Increment cnt to 3, add 2 to sum: s = 7 + 2 = 9
    • Since 2 * 2 ≠ 6, we also have divisor 6 // 2 = 3
    • Increment cnt to 4, add 3 to sum: s = 9 + 3 = 12
  3. Stop at i = 3 since 3 * 3 = 9 > 6
  4. Final: cnt = 4, so return sum of 12

Processing third number: 8

  1. Initialize: cnt = 2, s = 8 + 1 = 9 (divisors 1 and 8)
  2. Check i = 2: 8 % 2 = 0, so 2 is a divisor
    • Increment cnt to 3, add 2 to sum: s = 9 + 2 = 11
    • Since 2 * 2 ≠ 8, we also have divisor 8 // 2 = 4
    • Increment cnt to 4, add 4 to sum: s = 11 + 4 = 15
  3. Stop at i = 3 since 3 * 3 = 9 > 8
  4. Final: cnt = 4, so return sum of 15

Total Result: 32 + 12 + 15 = 59

The key insight is that by checking only up to √n and handling divisor pairs together, we efficiently find all divisors while minimizing iterations.

Solution Implementation

1class Solution:
2    def sumFourDivisors(self, nums: List[int]) -> int:
3        """
4        Calculate the sum of divisors for all numbers in nums that have exactly 4 divisors.
5      
6        Args:
7            nums: List of integers to check
8          
9        Returns:
10            Sum of all divisors for numbers with exactly 4 divisors
11        """
12      
13        def get_divisor_sum_if_four(number: int) -> int:
14            """
15            Calculate sum of divisors if the number has exactly 4 divisors, otherwise return 0.
16          
17            Args:
18                number: Integer to check divisors for
19              
20            Returns:
21                Sum of divisors if count is 4, otherwise 0
22            """
23            # Start with divisor 2 (we'll count 1 and number separately)
24            divisor = 2
25          
26            # Initialize with 1 and the number itself as divisors
27            divisor_count = 2
28            divisor_sum = number + 1
29          
30            # Check divisors up to sqrt(number)
31            while divisor <= number // divisor:
32                if number % divisor == 0:
33                    # Found a divisor
34                    divisor_count += 1
35                    divisor_sum += divisor
36                  
37                    # Check if the complementary divisor is different
38                    if divisor * divisor != number:
39                        # Add the complementary divisor (number // divisor)
40                        divisor_count += 1
41                        divisor_sum += number // divisor
42              
43                divisor += 1
44          
45            # Return sum only if exactly 4 divisors found
46            return divisor_sum if divisor_count == 4 else 0
47      
48        # Apply the function to all numbers and sum the results
49        return sum(get_divisor_sum_if_four(number) for number in nums)
50
1class Solution {
2    /**
3     * Calculates the sum of all divisors for numbers that have exactly 4 divisors.
4     * @param nums Array of integers to process
5     * @return Sum of divisors for all numbers with exactly 4 divisors
6     */
7    public int sumFourDivisors(int[] nums) {
8        int totalSum = 0;
9      
10        // Process each number in the array
11        for (int number : nums) {
12            totalSum += getSumIfFourDivisors(number);
13        }
14      
15        return totalSum;
16    }
17
18    /**
19     * Calculates the sum of divisors if the number has exactly 4 divisors.
20     * @param number The number to check
21     * @return Sum of all divisors if count is 4, otherwise 0
22     */
23    private int getSumIfFourDivisors(int number) {
24        // Initialize with 2 divisors (1 and the number itself)
25        int divisorCount = 2;
26        int divisorSum = number + 1;  // Sum includes 1 and the number itself
27      
28        // Check for divisors from 2 to sqrt(number)
29        for (int i = 2; i <= number / i; ++i) {
30            if (number % i == 0) {
31                // Found a divisor i
32                ++divisorCount;
33                divisorSum += i;
34              
35                // Check if the complementary divisor (number/i) is different from i
36                if (i * i != number) {
37                    // Add the complementary divisor
38                    ++divisorCount;
39                    divisorSum += number / i;
40                }
41            }
42        }
43      
44        // Return sum only if exactly 4 divisors found, otherwise return 0
45        return divisorCount == 4 ? divisorSum : 0;
46    }
47}
48
1class Solution {
2public:
3    int sumFourDivisors(vector<int>& nums) {
4        int totalSum = 0;
5      
6        // Process each number in the array
7        for (int number : nums) {
8            totalSum += getSumIfExactlyFourDivisors(number);
9        }
10      
11        return totalSum;
12    }
13
14private:
15    int getSumIfExactlyFourDivisors(int number) {
16        // Initialize with 2 divisors (1 and the number itself)
17        int divisorCount = 2;
18        int divisorSum = 1 + number;
19      
20        // Check for divisors from 2 to sqrt(number)
21        for (int i = 2; i * i <= number; ++i) {
22            if (number % i == 0) {
23                // Found a divisor
24                divisorCount++;
25                divisorSum += i;
26              
27                // Check if the corresponding divisor is different
28                // (avoid counting perfect squares twice)
29                if (i * i != number) {
30                    divisorCount++;
31                    divisorSum += number / i;
32                }
33            }
34        }
35      
36        // Return the sum only if there are exactly 4 divisors
37        return (divisorCount == 4) ? divisorSum : 0;
38    }
39};
40
1/**
2 * Calculates the sum of all divisors for numbers that have exactly 4 divisors
3 * @param nums - Array of positive integers to check
4 * @returns Sum of divisors for all numbers with exactly 4 divisors
5 */
6function sumFourDivisors(nums: number[]): number {
7    /**
8     * Helper function to find the sum of divisors if a number has exactly 4 divisors
9     * @param num - The number to check for divisors
10     * @returns Sum of all divisors if count is 4, otherwise 0
11     */
12    const getSumIfFourDivisors = (num: number): number => {
13        // Start with 2 divisors (1 and the number itself)
14        let divisorCount: number = 2;
15        // Initialize sum with 1 and the number itself
16        let divisorSum: number = num + 1;
17      
18        // Check all potential divisors from 2 to sqrt(num)
19        for (let divisor: number = 2; divisor * divisor <= num; ++divisor) {
20            if (num % divisor === 0) {
21                // Found a divisor, increment count and add to sum
22                ++divisorCount;
23                divisorSum += divisor;
24              
25                // Check if we need to add the complementary divisor
26                // (avoid counting the same divisor twice when num is a perfect square)
27                if (divisor * divisor !== num) {
28                    ++divisorCount;
29                    divisorSum += Math.floor(num / divisor);
30                }
31            }
32        }
33      
34        // Return sum only if there are exactly 4 divisors
35        return divisorCount === 4 ? divisorSum : 0;
36    };
37  
38    // Accumulate the sum of divisors for all valid numbers
39    let totalSum: number = 0;
40    for (const num of nums) {
41        totalSum += getSumIfFourDivisors(num);
42    }
43  
44    return totalSum;
45}
46

Time and Space Complexity

The time complexity is O(n × √m), where n is the length of the array and m represents the maximum value in the array. For each number x in the array, the helper function f(x) iterates from i = 2 to i <= x // i (which is equivalent to i <= √x), resulting in O(√x) iterations per number. Since we process all n numbers in the array, the overall time complexity is O(n × √m).

The space complexity is O(1). The algorithm only uses a constant amount of extra space for variables i, cnt, and s in the helper function, regardless of the input size. The generator expression sum(f(x) for x in nums) processes elements one at a time without storing intermediate results, maintaining constant space usage.

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

Common Pitfalls

1. Incorrect Initialization of Divisor Count

A common mistake is initializing the divisor count to 0 or 1 instead of 2. Since every positive integer has at least two divisors (1 and itself), we should start with divisor_count = 2. Starting from 0 would require explicitly checking for 1 and the number itself, which adds unnecessary complexity.

Wrong approach:

divisor_count = 0  # Incorrect - forgets to count 1 and n
# or
divisor_count = 1  # Incorrect - forgets to count either 1 or n

Correct approach:

divisor_count = 2  # Accounts for 1 and the number itself
divisor_sum = number + 1  # Sum includes both 1 and the number

2. Double-Counting in Perfect Square Cases

When a number is a perfect square (like 4, 9, 16), the square root is counted as a single divisor, not two. Failing to check divisor * divisor != number would count the square root twice.

Wrong approach:

if number % divisor == 0:
    divisor_count += 2  # Always adds 2 - wrong for perfect squares!
    divisor_sum += divisor + (number // divisor)

Correct approach:

if number % divisor == 0:
    divisor_count += 1
    divisor_sum += divisor
    if divisor * divisor != number:  # Only add complement if not square root
        divisor_count += 1
        divisor_sum += number // divisor

3. Loop Boundary Issues

Using divisor < number // divisor (strict inequality) instead of divisor <= number // divisor would miss the square root for perfect squares. Alternatively, iterating all the way to number-1 would be inefficient and could cause timeout for large inputs.

Wrong approaches:

# Misses square root for perfect squares
while divisor < number // divisor:  

# Inefficient - O(n) instead of O(√n)
while divisor < number:  

Correct approach:

while divisor <= number // divisor:  # Includes square root when needed

4. Starting Loop from Wrong Value

Starting the divisor check from 1 instead of 2 would duplicate the work since we already account for 1 in initialization. This doesn't break correctness but adds unnecessary iterations.

Less efficient:

divisor = 1  # Unnecessary - we already counted 1
while divisor <= number // divisor:
    if divisor == 1:  # Extra check needed
        continue

More efficient:

divisor = 2  # Start from 2 since 1 is already counted

5. Handling Edge Cases

Not properly handling small numbers (1, 2, 3) or negative numbers in the input array could lead to incorrect results. The number 1 has only one divisor (itself), and prime numbers have exactly two divisors.

Solution: The current implementation naturally handles these cases:

  • Number 1: Has 1 divisor, returns 0 (correct)
  • Prime numbers: Have 2 divisors, return 0 (correct)
  • Numbers with exactly 4 divisors work as expected
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which of the tree traversal order can be used to obtain elements in a binary search tree in sorted order?


Recommended Readings

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

Load More