
Problem Statement
In this scenario, a positive integer is classified as magical if it can be cleanly divided by either integer a
or integer b
. The challenge is to compute the nth
magical number when provided with three integers: n
, a
, and b
.
Given that the resulting magical number could potentially be very large, the result should be returned after being taken modulo 10^9 + 7
. The task requires determining the sequence of numbers divisible by a
or b
and then isolating the nth
element of this sequence.
Examples
Example 1
Input:
n = 1, a = 2, b = 3
Output:
2
Explanation:
The first number divisible by either 2 or 3 is 2.
Example 2
Input:
n = 4, a = 2, b = 3
Output:
6
Explanation:
The magical numbers in order are: 2, 3, 4, 6. The fourth magical number is 6.
Constraints
1 <= n <= 10^9
2 <= a, b <= 4 * 10^4
Approach and Intuition
The goal is to identify every number that is divisible by a
or b
, sequence them in ascending order, and select the nth
number from this list.
Binary Search for the nth Magical Number:
- Direct enumeration up to
n
is inefficient given the constraints. - Instead, use binary search to find the smallest number
x
such that there are at leastn
magical numbers ≤x
.
- Direct enumeration up to
Count of Magical Numbers ≤ x:
Use the inclusion-exclusion principle:
- Count of numbers divisible by
a
:x // a
- Count of numbers divisible by
b
:x // b
- Subtract overlap (divisible by both):
x // lcm(a, b)
- Total =
x // a + x // b - x // lcm(a, b)
- Count of numbers divisible by
Least Common Multiple (LCM):
- Calculate LCM of
a
andb
using:lcm = (a * b) // gcd(a, b)
- Calculate LCM of
Apply Modulo Operation:
- Return the result as
x % (10^9 + 7)
once the nth magical number is found.
- Return the result as
This method ensures the solution is efficient even for large input sizes and adheres to the required time complexity.
Solutions
- C++
class Solution {
public:
int findNthMagicNumber(int position, int first, int second) {
int modulo = 1000000007;
int leastCommonMultiple = first / greatestCommonDivisor(first, second) * second;
long low = 0;
long high = (long)position * std::min(first, second);
while (low < high) {
long mid = low + (high - low) / 2;
if (mid / first + mid / second - mid / leastCommonMultiple < position)
low = mid + 1;
else
high = mid;
}
return (int)(low % modulo);
}
int greatestCommonDivisor(int a, int b) {
if (a == 0) return b;
return greatestCommonDivisor(b % a, a);
}
};
This C++ solution implements a function to find the Nth magical number. A magical number is defined as a positive integer that is divisible by either of two given numbers. The solution uses binary search to efficiently find the desired magical number, leveraging mathematical principles such as the greatest common divisor (GCD) and least common multiple (LCM).
- Calculation of LCM: Computes the least common multiple using the formula
LCM(a, b) = a / GCD(a, b) * b
, ensuring that the calculation handles potential overflows by dividing before multiplying. - Binary Search Approach:
- Establishes a search range from 0 to
position * min(first, second)
. - Uses a binary search to find the smallest number such that the count of magical numbers up to that point is at least the desired position.
- Establishes a search range from 0 to
- Result Normalization: The result is modulo
1000000007
to ensure it fits within typical integer type limits and to comply with constraints that are often set in programming contests or systems.
Function Implementation:
findNthMagicNumber()
main function for finding the Nth magical number and modulo operation to conform with constraints.greatestCommonDivisor()
, a helper function necessary for the LCM calculation, implemented recursively.
This approach ensures that the time complexity is reduced compared to a direct computation method, which would be inefficient for large inputs. The use of fundamental number theory concepts like GCD and LCM is critical for optimizing the solution's efficiency.
- Java
class Solution {
public int findNthMagicalNumber(int N, int X, int Y) {
int MODULO = 1_000_000_007;
int lcmValue = X / calculateGCD(X, Y) * Y;
long low = 0;
long high = (long) N * Math.min(X, Y);
while (low < high) {
long mid = low + (high - low) / 2;
if (mid / X + mid / Y - mid / lcmValue < N)
low = mid + 1;
else
high = mid;
}
return (int) (low % MODULO);
}
private int calculateGCD(int a, int b) {
if (a == 0) return b;
return calculateGCD(b % a, a);
}
}
The provided Java solution computes the Nth magical number where a number is considered magical if it is divisible by either of two given positive integers X or Y.
Here’s a breakdown of the solution:
Define the
findNthMagicalNumber
method which takes three parameters: N (the Nth magical number to find), X, and Y.An integer
MODULO
is introduced to ensure the result remains within the bounds of integer values typically used in programming contests.Calculate the least common multiple (LCM) of X and Y using the GCD method, leveraging the relationship LCM(X, Y) = (X * Y) / GCD(X, Y). This is used to adjust for numbers that are counted twice (divisible by both X and Y).
Implement a binary search between 0 and N * min(X, Y). The upper bound assumes the worst-case scenario with the smallest among X and Y.
During each iteration of the binary search, set the mid-value and calculate the magical numbers up to mid using the formula: (mid / X) + (mid / Y) - (mid / lcmValue). Adjust the low and high pointers based on whether the current mid-value produces fewer than N magical numbers.
Return the smallest number that has exactly N numbers less than it that are multiples of either X or Y, modulated by
1_000_000_007
to ensure it fits within typical bounds.
The helper method calculateGCD
uses the Euclidean algorithm to recursively find the greatest common divisor (GCD), which is essential for finding the LCM.
This solution efficiently finds the Nth magical number using mathematical properties and logarithmic searching—returning results in optimal time for large inputs.
- JavaScript
var magicalNumberAtIndex = function(index, first, second) {
const computeGCD = (num1, num2) => {
if (num1 == 0) return num2;
return computeGCD(num2 % num1, num1);
}
const MODULO = 1000000007;
const LCM = first / computeGCD(first, second) * second;
let lowerBound = 0;
let upperBound = index * Math.min(first, second);
while (lowerBound < upperBound) {
let middle = lowerBound + Math.trunc((upperBound - lowerBound) / 2);
// Check if the count of magical numbers below middle is less than index
if (Math.trunc(middle/first) + Math.trunc(middle/second) - Math.trunc(middle/LCM) < index)
lowerBound = middle + 1;
else
upperBound = middle;
}
return lowerBound % MODULO;
};
In the JavaScript solution to the problem of finding the Nth magical number, the approach utilizes binary search and number theory concepts such as Greatest Common Divisor (GCD) and Least Common Multiple (LCM). Here's how the solution works:
GCD Calculation: The solution defines an inner function
computeGCD
to compute the Greatest Common Divisor of two numbers using Euclid's algorithm. This helps in determining the LCM.LCM Computation: Using the calculated GCD, the solution then computes the Least Common Multiple of the two given numbers. The formula used is ( \text{LCM}(a, b) = \frac{a \times b}{\text{GCD}(a, b)} ).
Utilizing Binary Search: To find the Nth magical number, the solution employs binary search. The search space spans from 0 to ( \text{index} \times \min(\text{first}, \text{second}) ).
Binary Search Implementation:
It initializes the
lowerBound
to zero andupperBound
to ( \text{index} \times \min(\text{first}, \text{second}) ).The loop continues until
lowerBound
is not less thanupperBound
.On each iteration, the middle point is calculated, and the count of magical numbers below this midpoint is determined by considering individual counts from both numbers and adjusting for overlaps using the LCM.
If the number of magical numbers below the midpoint is less than the desired index, the search space is adjusted to explore higher numbers by setting
lowerBound
tomiddle + 1
. Otherwise,upperBound
becomesmiddle
.
Returning the Result: The final result is obtained by taking the modulo of
lowerBound
with (10^9 + 7), ensuring that the solution handles very large output gracefully.
This efficient method ensures that the Nth magical number is found in a logarithmic time complexity relative to the search bounds, making it apt for large inputs.
No comments yet.