leet code 1201. Ugly Number III.
Write a program to find the n
-th ugly number.
Ugly numbers are positive integers which are divisible by a
or b
or c
.
Example 1:
Input: n = 3, a = 2, b = 3, c = 5 Output: 4 Explanation: The ugly numbers are 2, 3, 4, 5, 6, 8, 9, 10... The 3rd is 4.
Example 2:
Input: n = 4, a = 2, b = 3, c = 4 Output: 6 Explanation: The ugly numbers are 2, 3, 4, 6, 8, 9, 12... The 4th is 6.
Example 3:
Input: n = 5, a = 2, b = 11, c = 13 Output: 10 Explanation: The ugly numbers are 2, 4, 6, 8, 10, 11, 12, 13... The 5th is 10.
Example 4:
INPUT: = n-1000000000, A = 2, B = 217 983 653, 336 916 467 C = the Output: 1999999984
Reference:
[. 1] leetcode at discuss: https://leetcode.com/problems/ugly-number-iii/discuss/387539/cpp- Search-with--Binary Picture-Binary-Search-and-Template
[2] Euclidean algorithm greatest common divisor: https://www.cnblogs.com/kirito-c/p/6910912.html (given the error codes gcd)
entitled: seeking can be a positive integer of n a or b or c divisible.
Translation: seeking argmin_N F (N), F ( N) = a or b, or c can be divisible, less than N, the counted number, F (N) == n
further, so that f (a) = be number less than N number divisible by a similar f (b), f (c ). So that G (a, b) a, b, the least common multiple.
Title then becomes: argmin_N F (N), F (N) = f (a) + f (b) + f (c) - f (g (a, b)) - f (g (a, c)) - f (g (b, c )) + f (g (a, b, c)), F (N) == n
Pirates a diagram to explain: a = f (a), b = f (b) and the like.
In this case involves two questions:
F 1. find how the number less than N can be a number divisible by (a)?
2. how find the least common multiple of a and b g (a, b)?
A: 1. N / a, that can be a number divisible by all may be expressed as p * a, p is a positive integer. All less than the number N is expressed as a value capable of f (a) of p * a number, and the value of p from 1 to N / a. Therefore, the answer is N / a
2. The least common multiple calculated as a * b / a and b the greatest common divisor. The greatest common divisor by the Euclidean algorithm can be, that is, Euclidean algorithm to solve.
Generally understood as follows: If there is a large number of small and a number b, if a% b == 0, then b is the greatest common divisor of a and b.
! If a% b = 0, assuming a = q * b + r, r is the remainder, and a = s * t, b = u * t, t is a divisor of a and b, there is r = (s - q * u) * t, t is a divisor of the number indicates that the remainder a and b. Therefore, the greatest common divisor of b and r is the greatest common divisor of a and b. Such recursion, at a time when the remainder is 0, the divisor is the greatest common divisor.
Code can be written as:
int gcd(int a, int b){ int r = 0; while (b){ r = a % b; a = b; b = r; } return a; }
After obtaining the calculated f and g, can find the condition of minimum N F (N) == n of the. It can be seen F (N) is a monotonic function, i.e., if M> = N, there are F (M)> = F (N).
This is similar to the index to find the value of n elements in an ordered array. F (N) is an array, N is its index. Therefore, you can use binary search.
insomniacat provides the basic framework for the binary search:
while(lo < hi) { int mid = lo + (hi - lo) / 2; if(Special condition passed)(optional): return mid; if(condition passed) hi = mid; else lo = mid + 1; } return lo;
The final code:
class Solution { public: int nthUglyNumber(int n, int a, int b, int c) { int lo = 1, hi = 2 * (int)1e9; long A = a, B = b, C = c; long AB = A * B / gcd(A, B); long AC = A * C / gcd(A, C); long BC = B * C / gcd(B, C); long ABC = A * BC / gcd(A, BC); while (lo < hi){ int mid = (hi - lo) / 2 + lo; // compute F(N) long FN = mid / A + mid / B + mid / C - mid / AB - mid / AC - mid / BC + mid / ABC; if (FN < n) lo = mid + 1; else hi = mid; } return lo; } int gcd(long a, long b){ int r; while (b){ r = a % b; a = b; b = r; } return a; } };