2513. Minimize the Maximum of Two Arrays
Problem Description
You need to create two arrays arr1 and arr2 by adding positive integers to them according to specific rules:
Rules for arr1:
- Must contain exactly
uniqueCnt1distinct positive integers - Each integer in
arr1must NOT be divisible bydivisor1
Rules for arr2:
- Must contain exactly
uniqueCnt2distinct positive integers - Each integer in
arr2must NOT be divisible bydivisor2
Additional constraint:
- The two arrays must be completely disjoint (no integer can appear in both arrays)
Given the parameters divisor1, divisor2, uniqueCnt1, and uniqueCnt2, you need to find the minimum possible value of the maximum integer across both arrays.
In other words, if you optimally choose which positive integers to place in each array while satisfying all constraints, what's the smallest possible value for the largest number you'll need to use?
Example to clarify:
If divisor1 = 2, divisor2 = 3, uniqueCnt1 = 1, uniqueCnt2 = 1:
arr1needs 1 number not divisible by 2 (could use 1, 3, 5, 7, ...)arr2needs 1 number not divisible by 3 (could use 1, 2, 4, 5, ...)- Since arrays can't share numbers, one optimal solution is
arr1 = [1]andarr2 = [2] - The maximum value used is 2, which would be the answer
Intuition
The key insight is that if we have a maximum value x, we can determine whether it's possible to construct valid arrays with all numbers ≤ x.
Think about what numbers are available up to x:
- For
arr1: We can use all positive integers up toxthat are NOT divisible bydivisor1 - For
arr2: We can use all positive integers up toxthat are NOT divisible bydivisor2
How many such numbers exist? If we have x total numbers:
- Numbers divisible by
divisor1:x // divisor1 - Numbers NOT divisible by
divisor1:x - (x // divisor1) - Similarly, numbers NOT divisible by
divisor2:x - (x // divisor2)
But there's a catch - some numbers might be valid for both arrays (not divisible by either divisor). Since we need disjoint arrays, we must carefully distribute these "flexible" numbers.
The critical observation is that numbers divisible by both divisor1 and divisor2 (i.e., divisible by lcm(divisor1, divisor2)) can't go in either array. So the total available numbers for both arrays combined is x minus the count of numbers divisible by the LCM.
This transforms our problem into a binary search question: "What's the smallest x such that we can fill both arrays?" We can check if a given x works by:
- Counting how many valid numbers exist for
arr1only - Counting how many valid numbers exist for
arr2only - Counting how many numbers are valid for either array (flexible numbers)
- Verifying we have enough numbers to satisfy both
uniqueCnt1anduniqueCnt2
Since we want the minimum possible maximum, binary search naturally finds the smallest x where this becomes feasible.
Learn more about Math and Binary Search patterns.
Solution Implementation
1from math import lcm
2
3class Solution:
4 def minimizeSet(
5 self, divisor1: int, divisor2: int, uniqueCnt1: int, uniqueCnt2: int
6 ) -> int:
7 """
8 Find the minimum possible maximum integer in two sets where:
9 - Set 1 needs uniqueCnt1 elements not divisible by divisor1
10 - Set 2 needs uniqueCnt2 elements not divisible by divisor2
11 - Elements must be positive integers and can't be in both sets
12 """
13 lcm_divisor = lcm(divisor1, divisor2)
14
15 def feasible(max_value: int) -> bool:
16 """
17 Check if we can form valid sets with maximum value <= max_value
18
19 For each set, count how many numbers from 1 to max_value
20 are not divisible by the respective divisor
21 """
22 # Count numbers from 1 to max_value not divisible by divisor1
23 available_for_set1 = max_value - (max_value // divisor1)
24
25 # Count numbers from 1 to max_value not divisible by divisor2
26 available_for_set2 = max_value - (max_value // divisor2)
27
28 # Count numbers from 1 to max_value not divisible by LCM of both divisors
29 available_for_both = max_value - (max_value // lcm_divisor)
30
31 # Check if all constraints can be satisfied
32 return (
33 available_for_set1 >= uniqueCnt1 and
34 available_for_set2 >= uniqueCnt2 and
35 available_for_both >= uniqueCnt1 + uniqueCnt2
36 )
37
38 # Binary search for the minimum value that satisfies all constraints
39 # Using the first_true_index template pattern
40 left, right = 1, 10**10
41 first_true_index = -1
42
43 while left <= right:
44 mid = (left + right) // 2
45 if feasible(mid):
46 first_true_index = mid
47 right = mid - 1
48 else:
49 left = mid + 1
50
51 return first_true_index
521class Solution {
2 /**
3 * Finds the minimum possible maximum value when creating two arrays with given constraints.
4 * Array1 cannot contain multiples of divisor1 and must have uniqueCnt1 distinct elements.
5 * Array2 cannot contain multiples of divisor2 and must have uniqueCnt2 distinct elements.
6 *
7 * @param divisor1 The divisor constraint for the first array
8 * @param divisor2 The divisor constraint for the second array
9 * @param uniqueCnt1 Required number of distinct elements in the first array
10 * @param uniqueCnt2 Required number of distinct elements in the second array
11 * @return The minimum possible maximum value among all elements in both arrays
12 */
13 public int minimizeSet(int divisor1, int divisor2, int uniqueCnt1, int uniqueCnt2) {
14 // Calculate LCM to find numbers divisible by both divisors
15 long leastCommonMultiple = lcm(divisor1, divisor2);
16
17 // Binary search using the first_true_index template pattern
18 long left = 1;
19 long right = 10_000_000_000L;
20 long firstTrueIndex = -1;
21
22 while (left <= right) {
23 long mid = left + (right - left) / 2;
24
25 // Count available numbers for array1 (not divisible by divisor1)
26 long availableForArray1 = mid - (mid / divisor1);
27
28 // Count available numbers for array2 (not divisible by divisor2)
29 long availableForArray2 = mid - (mid / divisor2);
30
31 // Count total available numbers (not divisible by LCM)
32 long totalAvailable = mid - (mid / leastCommonMultiple);
33
34 // Check if current mid value satisfies all constraints (feasible condition)
35 if (availableForArray1 >= uniqueCnt1 &&
36 availableForArray2 >= uniqueCnt2 &&
37 totalAvailable >= uniqueCnt1 + uniqueCnt2) {
38 // Mid is feasible, record it and search for smaller value
39 firstTrueIndex = mid;
40 right = mid - 1;
41 } else {
42 // Mid is not feasible, search for larger value
43 left = mid + 1;
44 }
45 }
46
47 return (int) firstTrueIndex;
48 }
49
50 /**
51 * Calculates the least common multiple of two integers.
52 */
53 private long lcm(int a, int b) {
54 return (long) a * b / gcd(a, b);
55 }
56
57 /**
58 * Calculates the greatest common divisor using Euclidean algorithm.
59 */
60 private int gcd(int a, int b) {
61 return b == 0 ? a : gcd(b, a % b);
62 }
63}
641class Solution {
2public:
3 int minimizeSet(int divisor1, int divisor2, int uniqueCnt1, int uniqueCnt2) {
4 // Calculate LCM of both divisors to handle numbers divisible by both
5 long long lcmValue = lcm(static_cast<long long>(divisor1), static_cast<long long>(divisor2));
6
7 // Binary search using the first_true_index template pattern
8 long long left = 1;
9 long long right = 10000000000LL;
10 long long firstTrueIndex = -1;
11
12 while (left <= right) {
13 long long mid = left + (right - left) / 2;
14
15 // Count numbers from 1 to mid that are NOT divisible by divisor1
16 long long availableForSet1 = mid - (mid / divisor1);
17
18 // Count numbers from 1 to mid that are NOT divisible by divisor2
19 long long availableForSet2 = mid - (mid / divisor2);
20
21 // Count numbers from 1 to mid that are NOT divisible by either divisor
22 long long availableForBoth = mid - (mid / lcmValue);
23
24 // Check if current mid value satisfies all constraints (feasible condition)
25 if (availableForSet1 >= uniqueCnt1 &&
26 availableForSet2 >= uniqueCnt2 &&
27 availableForBoth >= uniqueCnt1 + uniqueCnt2) {
28 // Mid is feasible, record it and search for smaller value
29 firstTrueIndex = mid;
30 right = mid - 1;
31 } else {
32 // Mid is not feasible, search for larger value
33 left = mid + 1;
34 }
35 }
36
37 return firstTrueIndex;
38 }
39};
401function minimizeSet(divisor1: number, divisor2: number, uniqueCnt1: number, uniqueCnt2: number): number {
2 // Calculate LCM of both divisors to handle numbers divisible by both
3 const lcmValue = lcm(divisor1, divisor2);
4
5 // Binary search using the first_true_index template pattern
6 let left = 1;
7 let right = 10000000000;
8 let firstTrueIndex = -1;
9
10 while (left <= right) {
11 const mid = Math.floor((left + right) / 2);
12
13 // Count numbers from 1 to mid that are NOT divisible by divisor1
14 const availableForSet1 = mid - Math.floor(mid / divisor1);
15
16 // Count numbers from 1 to mid that are NOT divisible by divisor2
17 const availableForSet2 = mid - Math.floor(mid / divisor2);
18
19 // Count numbers from 1 to mid that are NOT divisible by either divisor
20 const availableForBoth = mid - Math.floor(mid / lcmValue);
21
22 // Check if current mid value satisfies all constraints (feasible condition)
23 if (availableForSet1 >= uniqueCnt1 &&
24 availableForSet2 >= uniqueCnt2 &&
25 availableForBoth >= uniqueCnt1 + uniqueCnt2) {
26 // Mid is feasible, record it and search for smaller value
27 firstTrueIndex = mid;
28 right = mid - 1;
29 } else {
30 // Mid is not feasible, search for larger value
31 left = mid + 1;
32 }
33 }
34
35 return firstTrueIndex;
36}
37
38// Helper function to calculate the greatest common divisor
39function gcd(a: number, b: number): number {
40 while (b !== 0) {
41 const temp = b;
42 b = a % b;
43 a = temp;
44 }
45 return a;
46}
47
48// Helper function to calculate the least common multiple
49function lcm(a: number, b: number): number {
50 return Math.floor((a * b) / gcd(a, b));
51}
52Solution Approach
The solution uses binary search with the first_true_index template pattern to find the minimum possible maximum value. Here's how the implementation works:
Binary Search Template Setup:
We use the standard template with left, right, and first_true_index:
left, right = 1, 10**10 first_true_index = -1 while left <= right: mid = (left + right) // 2 if feasible(mid): first_true_index = mid right = mid - 1 else: left = mid + 1 return first_true_index
The Feasible Function:
For a given maximum value x, we calculate:
-
Count of valid numbers for arr1:
cnt1 = x // divisor1 * (divisor1 - 1) + x % divisor1- This formula counts numbers from 1 to
xthat are NOT divisible bydivisor1 - For every complete group of
divisor1numbers, we have(divisor1 - 1)valid ones - Plus any remaining numbers in the incomplete group (all are valid since they're less than
divisor1)
-
Count of valid numbers for arr2:
cnt2 = x // divisor2 * (divisor2 - 1) + x % divisor2- Same logic as above but for
divisor2
-
Count of numbers valid for either array:
divisor = lcm(divisor1, divisor2)(calculated once outside the function)cnt = x // divisor * (divisor - 1) + x % divisor- This counts numbers NOT divisible by the LCM (numbers that could potentially go in either array)
Validation Conditions:
The function returns True if all three conditions are met:
cnt1 >= uniqueCnt1: Enough valid numbers exist forarr1cnt2 >= uniqueCnt2: Enough valid numbers exist forarr2cnt >= uniqueCnt1 + uniqueCnt2: Total available numbers (excluding those divisible by LCM) is sufficient for both arrays combined
The third condition is crucial - it ensures we have enough distinct numbers to fill both arrays without overlap, accounting for numbers that must go to specific arrays (those divisible by one divisor but not the other).
The binary search efficiently finds the smallest x where all conditions are satisfied, giving us the minimum possible maximum value.
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 a concrete example with divisor1 = 2, divisor2 = 3, uniqueCnt1 = 3, uniqueCnt2 = 2.
We need:
arr1: 3 distinct numbers not divisible by 2 (odd numbers)arr2: 2 distinct numbers not divisible by 3- The arrays must be disjoint
Binary Search Process:
Let's check if x = 7 works:
-
Count valid numbers for arr1 (not divisible by 2):
- Numbers 1-7: {1, 2, 3, 4, 5, 6, 7}
- Not divisible by 2: {1, 3, 5, 7} → 4 numbers
- Using formula:
7 // 2 * (2-1) + 7 % 2 = 3 * 1 + 1 = 4✓
-
Count valid numbers for arr2 (not divisible by 3):
- Not divisible by 3: {1, 2, 4, 5, 7} → 5 numbers
- Using formula:
7 // 3 * (3-1) + 7 % 3 = 2 * 2 + 1 = 5✓
-
Count total available (not divisible by lcm(2,3) = 6):
- Not divisible by 6: {1, 2, 3, 4, 5, 7} → 6 numbers
- Using formula:
7 // 6 * (6-1) + 7 % 6 = 1 * 5 + 1 = 6✓
Validation:
cnt1 = 4 >= 3✓ (enough odd numbers for arr1)cnt2 = 5 >= 2✓ (enough non-multiples of 3 for arr2)cnt = 6 >= 3 + 2 = 5✓ (enough total distinct numbers)
All conditions met! But let's verify x = 6 doesn't work:
For x = 6:
- Valid for arr1: {1, 3, 5} → 3 numbers
- Valid for arr2: {1, 2, 4, 5} → 4 numbers
- Total available: {1, 2, 3, 4, 5} → 5 numbers (6 is divisible by lcm=6)
Conditions: 3 >= 3 ✓, 4 >= 2 ✓, 5 >= 5 ✓
Actually x = 6 works! Let's check x = 5:
- Valid for arr1: {1, 3, 5} → 3 numbers
- Valid for arr2: {1, 2, 4, 5} → 4 numbers
- Total available: {1, 2, 3, 4, 5} → 5 numbers
Conditions work, so let's try x = 4:
- Valid for arr1: {1, 3} → 2 numbers
- Valid for arr2: {1, 2, 4} → 3 numbers
- Total available: {1, 2, 3, 4} → 4 numbers
Conditions: 2 >= 3 ✗ FAILS!
Therefore, the minimum x is 5. One valid assignment would be:
arr1 = [1, 3, 5](3 odd numbers)arr2 = [2, 4](2 numbers not divisible by 3)
The maximum value used is 5, which is our answer.
Time and Space Complexity
Time Complexity: O(log(10^10) × log(divisor1 × divisor2))
The binary search using bisect_left searches in the range [0, 10^10), which takes O(log(10^10)) iterations. For each iteration, the function f(x) is called, which performs:
- Division and modulo operations with
divisor1,divisor2, anddivisor(LCM of divisor1 and divisor2):O(1) - The LCM calculation
lcm(divisor1, divisor2)involves computing the GCD using Euclidean algorithm:O(log(min(divisor1, divisor2)))
Since the LCM is calculated once outside the binary search, and assuming the LCM function internally uses GCD with time complexity O(log(divisor1 × divisor2)), the overall time complexity is O(log(divisor1 × divisor2) + log(10^10)), which simplifies to O(log(10^10)) as the dominant term.
Space Complexity: O(1)
The algorithm uses only a constant amount of extra space for:
- Variables
cnt1,cnt2,cntin functionf - Variable
divisorto store the LCM - The binary search mechanism in
bisect_leftusesO(1)space as it works with indices
The range(10^10) object is a generator that doesn't create the entire list in memory, so it contributes O(1) space.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
Pitfall 1: Using Wrong Binary Search Template Variant
The Problem:
A common mistake is using the while left < right with right = mid pattern instead of the standard template with first_true_index.
Why It Happens: Many developers learn different binary search variants and may default to a pattern that doesn't match the canonical template.
The Solution: Always use the first_true_index template pattern:
left, right = 1, 10**10 first_true_index = -1 while left <= right: mid = (left + right) // 2 if feasible(mid): first_true_index = mid right = mid - 1 else: left = mid + 1 return first_true_index
This template ensures consistency across all binary search problems and clearly tracks the answer in first_true_index.
Pitfall 2: Incorrect Counting of Available Numbers
The Problem:
A common mistake is incorrectly calculating how many numbers from 1 to x are not divisible by a given divisor. The naive approach might try to iterate and count, or use an incorrect formula like x - x // divisor which doesn't account for the pattern correctly.
Why It Happens:
The formula x - (x // divisor) seems intuitive - total numbers minus divisible numbers. However, this is exactly what we want! The confusion often comes from overthinking or trying to use modular arithmetic incorrectly, such as x // divisor * (divisor - 1) + x % divisor which would count incorrectly.
The Solution:
Use the straightforward formula: available = x - (x // divisor)
- This directly counts non-divisible numbers
- For example, with
x = 10anddivisor = 3: we have 10 - (10//3) = 10 - 3 = 7 numbers not divisible by 3 (which are: 1, 2, 4, 5, 7, 8, 10)
Pitfall 3: Forgetting the Disjoint Constraint
The Problem:
Some solutions only check if there are enough valid numbers for each array independently (available_for_set1 >= uniqueCnt1 and available_for_set2 >= uniqueCnt2) but forget to verify that we have enough total unique numbers to fill both arrays without overlap.
Why It Happens: It's easy to focus on each array's individual requirements and miss the global constraint that no number can appear in both arrays.
The Solution:
Always include the third condition: available_for_both >= uniqueCnt1 + uniqueCnt2
- This ensures the total pool of available numbers (those not divisible by LCM) is large enough
- Numbers divisible by only one divisor are forced into one specific array
- Numbers divisible by neither can go in either array, providing flexibility
Pitfall 4: Integer Overflow with LCM Calculation
The Problem:
When calculating lcm(divisor1, divisor2), the result can be very large, potentially causing integer overflow in languages with fixed integer sizes or leading to performance issues.
Why It Happens:
LCM can grow quickly. For example, if divisor1 = 10^5 and divisor2 = 10^5 - 1, the LCM could be close to 10^10.
The Solution:
- In Python, this is less of an issue due to arbitrary precision integers
- For other languages, use careful overflow checking or long/BigInteger types
- Consider using the formula:
lcm(a, b) = a * b // gcd(a, b)with GCD calculation to avoid intermediate overflow - Set appropriate upper bounds for binary search based on problem constraints
Pitfall 5: Inefficient Binary Search Bounds
The Problem:
Using an unnecessarily large search range like range(10**10) when a smaller bound would suffice, leading to more iterations than needed.
Why It Happens: Without analyzing the problem constraints, it's tempting to use a "safe" large number that will definitely contain the answer.
The Solution: Calculate a tighter upper bound based on the problem:
# The answer is at most the sum of counts plus some buffer for divisibility constraints
upper_bound = (uniqueCnt1 + uniqueCnt2) * max(divisor1, divisor2)
return bisect_left(range(upper_bound + 1), True, key=can_form_sets)
This reduces the number of binary search iterations while still guaranteeing correctness.
Which algorithm is best for finding the shortest distance between two points in an unweighted graph?
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
https assets algo monster cover_photos Binary_Search svg Binary Search Intuition Binary search is an efficient array search algorithm It works by narrowing down the search range by half each time If you have looked up a word in a physical dictionary you've already used binary search in real life Let's
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
Want a Structured Path to Master System Design Too? Don’t Miss This!