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.
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)
:
- Start iterating from
i = int(sqrt(x))
down to 1 - For each
i
, check ifx % i == 0
(i.e.,i
dividesx
evenly) - When we find the first divisor, return the pair
[i, x // i]
- Since we start from
√x
and move downward, the first divisor we find will give us the factor pair with minimum difference
Main Logic:
- Call
f(num + 1)
to get the best factor pair fornum + 1
, store in variablea
- Call
f(num + 2)
to get the best factor pair fornum + 2
, store in variableb
- Compare the absolute differences:
abs(a[0] - a[1])
vsabs(b[0] - b[1])
- 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 divisori
, the corresponding factorx // i
will be greater than or equal toi
- The first valid divisor we encounter gives us the most "balanced" factor pair
- Comparing results from both
num + 1
andnum + 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 EvaluatorExample 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
, soi = 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 fromint(sqrt(x))
down to 1, checking if each valuei
dividesx
evenly - In the worst case, the loop runs
O(√x)
iterations before finding a divisor pair - The function
f
is called twice: once withnum + 1
and once withnum + 2
- Since
num + 1
andnum + 2
are approximately equal tonum
, each call takesO(√num)
time - Two sequential
O(√num)
operations result inO(√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
, andb
- 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
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
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Don’t Miss This!