Facebook Pixel

1362. Closest Divisors

Problem Description

You are given an integer num. Your task is to find two integers whose product equals either num + 1 or num + 2. Among all possible pairs of integers that satisfy this condition, you need to return the pair that has the smallest absolute difference between them.

For example, if num = 8, you need to check:

  • For num + 1 = 9: The factor pairs are (1, 9) and (3, 3). The absolute differences are |1-9| = 8 and |3-3| = 0.
  • For num + 2 = 10: The factor pairs are (1, 10) and (2, 5). The absolute differences are |1-10| = 9 and |2-5| = 3.

Among all these pairs, (3, 3) has the smallest absolute difference of 0, so you would return [3, 3].

The key insight is that for any number, the factors that are closest to each other are those nearest to its square root. The solution efficiently finds these closest divisors by starting from √x and working downward until it finds a divisor. It then compares the results for both num + 1 and num + 2 to determine which produces the pair with the smaller absolute difference.

You can return the two integers in any order.

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

Intuition

To find two integers with the smallest absolute difference whose product equals a given number, we need to think about the mathematical relationship between factors. For any number x, its factors come in pairs: if i is a factor, then x/i is also a factor, and their product equals x.

The key observation is that among all factor pairs of a number, the pair closest to each other will be the one where both factors are nearest to √x. Why? Consider a number like 36:

  • Factor pairs: (1, 36), (2, 18), (3, 12), (4, 9), (6, 6)
  • The differences: |1-36| = 35, |2-18| = 16, |3-12| = 9, |4-9| = 5, |6-6| = 0

Notice how as we move toward √36 = 6, the difference keeps decreasing. This pattern holds for any number - the factors become more "balanced" as we approach the square root.

So our strategy becomes clear: start from √x and work downward to find the first number that divides x evenly. This will give us the factor pair with the minimum difference. We start from the square root and go down because we want the first (largest) divisor that's less than or equal to √x.

Since we need to check both num + 1 and num + 2, we apply this same logic to both values and then compare which result gives us the smaller absolute difference. This ensures we find the optimal pair across both possible target products.

Learn more about Math patterns.

Solution Approach

The solution implements a helper function f(x) that finds the two factors of x with the smallest absolute difference. Here's how the implementation works:

Helper Function f(x):

  1. Start iterating from i = int(sqrt(x)) down to 1
  2. For each i, check if x % i == 0 (i.e., i divides x evenly)
  3. When we find the first divisor, return the pair [i, x // i]
  4. Since we start from √x and move downward, the first divisor we find will give us the factor pair with minimum difference

Main Logic:

  1. Call f(num + 1) to get the best factor pair for num + 1, store in variable a
  2. Call f(num + 2) to get the best factor pair for num + 2, store in variable b
  3. Compare the absolute differences: abs(a[0] - a[1]) vs abs(b[0] - b[1])
  4. Return the pair with the smaller absolute difference

Why this works:

  • By starting from √x and going down, we ensure that when we find a divisor i, the corresponding factor x // i will be greater than or equal to i
  • The first valid divisor we encounter gives us the most "balanced" factor pair
  • Comparing results from both num + 1 and num + 2 ensures we find the globally optimal solution

Time Complexity: O(√n) for each call to f(x), where n is the value being factored 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 num = 8:

Step 1: Find closest divisors for num + 1 = 9

  • Start from i = √9 = 3
  • Check if 9 % 3 == 0? Yes!
  • First divisor found: i = 3
  • Return pair: [3, 9/3] = [3, 3]
  • Absolute difference: |3 - 3| = 0

Step 2: Find closest divisors for num + 2 = 10

  • Start from i = √10 ≈ 3.16, so i = 3
  • Check if 10 % 3 == 0? No
  • Decrement to i = 2
  • Check if 10 % 2 == 0? Yes!
  • First divisor found: i = 2
  • Return pair: [2, 10/2] = [2, 5]
  • Absolute difference: |2 - 5| = 3

Step 3: Compare and return the best pair

  • Pair from num + 1: [3, 3] with difference 0
  • Pair from num + 2: [2, 5] with difference 3
  • Since 0 < 3, return [3, 3]

The key insight illustrated here: by starting from the square root and working downward, we immediately find the most balanced factor pair. For 9, we hit the perfect square case right away. For 10, we skip over 3 (not a divisor) and find 2, which gives us the closest possible factors for that number.

Solution Implementation

1from typing import List
2from math import sqrt
3
4class Solution:
5    def closestDivisors(self, num: int) -> List[int]:
6        """
7        Find two integers whose product is either num+1 or num+2,
8        and whose absolute difference is minimized.
9      
10        Args:
11            num: The input integer
12          
13        Returns:
14            A list containing two integers with minimal absolute difference
15        """
16      
17        def find_closest_divisor_pair(target: int) -> List[int]:
18            """
19            Find the pair of divisors of target with minimal difference.
20            Start from sqrt(target) and work downwards to find the first divisor.
21          
22            Args:
23                target: The number to find divisors for
24              
25            Returns:
26                A list containing [smaller_divisor, larger_divisor]
27            """
28            # Start from sqrt(target) and iterate downwards
29            # The first divisor found will give the minimal difference
30            for divisor in range(int(sqrt(target)), 0, -1):
31                if target % divisor == 0:
32                    # Return both divisors as a pair
33                    return [divisor, target // divisor]
34      
35        # Find divisor pairs for both num+1 and num+2
36        divisors_num_plus_1 = find_closest_divisor_pair(num + 1)
37        divisors_num_plus_2 = find_closest_divisor_pair(num + 2)
38      
39        # Return the pair with smaller absolute difference
40        if abs(divisors_num_plus_1[0] - divisors_num_plus_1[1]) < abs(divisors_num_plus_2[0] - divisors_num_plus_2[1]):
41            return divisors_num_plus_1
42        else:
43            return divisors_num_plus_2
44
1class Solution {
2    /**
3     * Find two integers whose product is either num + 1 or num + 2,
4     * such that the absolute difference between them is minimized.
5     * 
6     * @param num The input number
7     * @return An array containing the two closest divisors
8     */
9    public int[] closestDivisors(int num) {
10        // Find closest divisor pair for num + 1
11        int[] divisorPairForNumPlusOne = findClosestDivisorPair(num + 1);
12      
13        // Find closest divisor pair for num + 2
14        int[] divisorPairForNumPlusTwo = findClosestDivisorPair(num + 2);
15      
16        // Return the pair with smaller absolute difference
17        int differenceForNumPlusOne = Math.abs(divisorPairForNumPlusOne[0] - divisorPairForNumPlusOne[1]);
18        int differenceForNumPlusTwo = Math.abs(divisorPairForNumPlusTwo[0] - divisorPairForNumPlusTwo[1]);
19      
20        return differenceForNumPlusOne < differenceForNumPlusTwo ? 
21               divisorPairForNumPlusOne : divisorPairForNumPlusTwo;
22    }
23
24    /**
25     * Find the pair of divisors of a number with minimum absolute difference.
26     * Start from sqrt(number) and work downwards to find the first divisor.
27     * This ensures the two divisors are as close as possible.
28     * 
29     * @param number The number to find divisors for
30     * @return An array containing two divisors with minimum difference
31     */
32    private int[] findClosestDivisorPair(int number) {
33        // Start from square root and work downwards
34        // The closer to sqrt, the smaller the difference between divisors
35        for (int divisor = (int) Math.sqrt(number); ; divisor--) {
36            // Check if current value is a divisor
37            if (number % divisor == 0) {
38                // Return both divisors as a pair
39                return new int[] {divisor, number / divisor};
40            }
41        }
42    }
43}
44
1class Solution {
2public:
3    vector<int> closestDivisors(int num) {
4        // Lambda function to find the pair of divisors with smallest difference
5        // Starting from sqrt(x) and going down ensures we find the closest pair first
6        auto findClosestDivisorPair = [](int x) {
7            // Start from sqrt(x) as this gives us the most balanced divisor pair
8            int sqrtValue = sqrt(x);
9            for (int divisor = sqrtValue;; --divisor) {
10                // Check if current number is a divisor
11                if (x % divisor == 0) {
12                    // Return the divisor pair
13                    return vector<int>{divisor, x / divisor};
14                }
15            }
16        };
17      
18        // Find divisor pairs for num + 1 and num + 2
19        vector<int> divisorPair1 = findClosestDivisorPair(num + 1);
20        vector<int> divisorPair2 = findClosestDivisorPair(num + 2);
21      
22        // Return the pair with smaller absolute difference
23        return abs(divisorPair1[0] - divisorPair1[1]) < abs(divisorPair2[0] - divisorPair2[1]) 
24               ? divisorPair1 : divisorPair2;
25    }
26};
27
1function closestDivisors(num: number): number[] {
2    /**
3     * Helper function to find the pair of divisors with the smallest difference
4     * for a given number. Starts from sqrt(x) and decrements to find the most
5     * balanced divisor pair (closest in value to each other).
6     * @param x - The number to find divisors for
7     * @returns Array containing the two divisors
8     */
9    const findClosestDivisorPair = (x: number): number[] => {
10        // Start from the square root of x, as divisors closest to sqrt(x)
11        // will have the smallest difference between them
12        const sqrtValue = Math.floor(Math.sqrt(x));
13      
14        // Iterate from sqrt(x) downwards to find the first valid divisor
15        for (let divisor = sqrtValue; divisor >= 1; divisor--) {
16            // Check if current number divides x evenly
17            if (x % divisor === 0) {
18                // Return both divisors as a pair
19                return [divisor, x / divisor];
20            }
21        }
22      
23        // This should never be reached, but return default for safety
24        return [1, x];
25    };
26  
27    // Find the closest divisor pairs for both num + 1 and num + 2
28    const divisorPair1 = findClosestDivisorPair(num + 1);
29    const divisorPair2 = findClosestDivisorPair(num + 2);
30  
31    // Calculate the absolute differences for both pairs
32    const difference1 = Math.abs(divisorPair1[0] - divisorPair1[1]);
33    const difference2 = Math.abs(divisorPair2[0] - divisorPair2[1]);
34  
35    // Return the pair with the smaller absolute difference
36    return difference1 < difference2 ? divisorPair1 : divisorPair2;
37}
38

Time and Space Complexity

The time complexity is O(√num), and the space complexity is O(1).

Time Complexity Analysis:

  • The function f(x) iterates from int(sqrt(x)) down to 1, checking if each value i divides x evenly
  • In the worst case, the loop runs O(√x) iterations before finding a divisor pair
  • The function f is called twice: once with num + 1 and once with num + 2
  • Since num + 1 and num + 2 are approximately equal to num, each call takes O(√num) time
  • Two sequential O(√num) operations result in O(√num) + O(√num) = O(√num) total time complexity

Space Complexity Analysis:

  • The function uses only a constant amount of extra space for variables i, a, and b
  • The returned list contains exactly 2 elements regardless of input size
  • No recursive calls or data structures that grow with input size are used
  • Therefore, the space complexity is O(1)

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

Common Pitfalls

1. Integer Overflow in Square Root Calculation

When dealing with very large values of num, calculating int(sqrt(target)) might lose precision due to floating-point arithmetic. For example, if target is a perfect square like 10^18, the floating-point representation of its square root might be slightly off (e.g., 999999999.9999999 instead of 1000000000), causing int() to truncate incorrectly.

Solution: Use integer-based methods or add a small epsilon for rounding:

def find_closest_divisor_pair(target: int) -> List[int]:
    # Add 0.5 for proper rounding to handle floating-point precision issues
    sqrt_val = int(sqrt(target) + 0.5)
  
    # Check if sqrt_val is actually a divisor (handles perfect squares)
    if sqrt_val * sqrt_val == target:
        return [sqrt_val, sqrt_val]
  
    # Otherwise, start from floor(sqrt(target))
    for divisor in range(int(sqrt(target)), 0, -1):
        if target % divisor == 0:
            return [divisor, target // divisor]

2. Edge Case: num = 0

When num = 0, we need to find divisors of 1 or 2. The code works correctly but it's worth noting that:

  • For num + 1 = 1: The only factor pair is (1, 1)
  • For num + 2 = 2: The factor pairs are (1, 2)

The algorithm handles this correctly, but developers might overlook testing this edge case.

3. Assumption About Return Order

The problem states "You can return the two integers in any order," but the current implementation always returns [smaller, larger]. While this is consistent and correct, some developers might assume they need to preserve a specific order based on which number (num+1 or num+2) was used.

Solution: Document the return order clearly or make it explicit:

# Always returns [smaller_divisor, larger_divisor] for consistency
return sorted([divisor, target // divisor])

4. Performance Issue with Very Large Numbers

For extremely large values of num, iterating from sqrt(target) down to 1 could still be slow if the number is prime or has only large prime factors. For instance, if num + 1 is prime, we'd iterate all the way down to 1.

Solution: Add an early termination optimization when the difference becomes larger than the best found so far:

def closestDivisors(self, num: int) -> List[int]:
    best_pair = None
    best_diff = float('inf')
  
    for target in [num + 1, num + 2]:
        sqrt_val = int(sqrt(target))
        for divisor in range(sqrt_val, 0, -1):
            if target % divisor == 0:
                other = target // divisor
                diff = other - divisor
                if diff < best_diff:
                    best_diff = diff
                    best_pair = [divisor, other]
                break  # Found best for this target
      
        # Early termination: if we found factors with diff 0 or 1
        if best_diff <= 1:
            break
  
    return best_pair
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

What is the best way of checking if an element exists in an unsorted array once in terms of time complexity? Select the best that applies.


Recommended Readings

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

Load More