|
56 | 56 |
|
57 | 57 | <!-- 这里可写通用的实现逻辑 --> |
58 | 58 |
|
| 59 | +**方法一:二分搜索** |
| 60 | + |
| 61 | +根据题目提示结果在 [1, 2 * 10<sup>9</sup>] 的闭区间上,所以定义二分搜索的左边界 left=1,右边界 right=2e9。此时我们只需要在 [left,right] 的闭区间内找到一个最小的数 num,使其满足 [1,num] 内的丑数总数等于 n,则 num 就是第 n 个丑数。计算在 [1,num] 的范围内丑数的数目,即可以被 a、b 或 c 任意一个数整除的数的总数,其方法如下: |
| 62 | + |
| 63 | +`f(num, a, b, c) = num/a + num/b + num/c - a⋂b - a⋂c - b⋂c + a⋂b⋂c` |
| 64 | + |
| 65 | +- num/a 表示在 [1,num] 内可以整除 a 的数目,num/b 表示在 [1,num] 内可以整除 b 的数目,num/c 表示在 [1,num] 内可以整除 c 的数目。 |
| 66 | +- a⋂b 表示在 [1,num] 内可以同时整除 a 和 b 的数目,a⋂c 表示在 [1,num] 内可以同时整除 a 和 c 的数,b⋂c 表示在 [1,num] 内可以同时整除 b 和 c 的数。 |
| 67 | +- a⋂b⋂c 表示在 [1,num] 内可以同时整除 a、b 和 c 的数。 |
| 68 | +- a⋂b = num/least_common_multiple(a, b),其他情况依次类推。 |
| 69 | + |
59 | 70 | <!-- tabs:start --> |
60 | 71 |
|
61 | 72 | ### **Python3** |
62 | 73 |
|
63 | 74 | <!-- 这里可写当前语言的特殊实现逻辑 --> |
64 | 75 |
|
65 | 76 | ```python |
66 | | - |
| 77 | +class Solution: |
| 78 | + def f(self, num: int, a: int, b: int, c: int) -> int: |
| 79 | + return num // a + num // b + num // c - num // math.lcm(a, b) - num // math.lcm(a, c) - num // math.lcm(b, c) \ |
| 80 | + + num // math.lcm(a, b, c) |
| 81 | + |
| 82 | + def nthUglyNumber(self, n: int, a: int, b: int, c: int) -> int: |
| 83 | + left, right = 1, int(2e9) |
| 84 | + while left <= right: |
| 85 | + mid = left + (right - left) // 2 |
| 86 | + if self.f(mid, a, b, c) < n: |
| 87 | + left = mid + 1 |
| 88 | + else: |
| 89 | + right = mid - 1 |
| 90 | + return left |
67 | 91 | ``` |
68 | 92 |
|
69 | | -### **Java** |
| 93 | +### **Go** |
70 | 94 |
|
71 | 95 | <!-- 这里可写当前语言的特殊实现逻辑 --> |
72 | 96 |
|
73 | | -```java |
| 97 | +```go |
| 98 | +func nthUglyNumber(n int, a int, b int, c int) int { |
| 99 | + left, right := 1, int(2e9) |
| 100 | + for left <= right { |
| 101 | + mid := left + (right-left)/2 |
| 102 | + if f(mid, a, b, c) < n { |
| 103 | + left = mid + 1 |
| 104 | + } else { |
| 105 | + right = mid - 1 |
| 106 | + } |
| 107 | + } |
| 108 | + return left |
| 109 | +} |
| 110 | + |
| 111 | +func f(num int, a int, b int, c int) int { |
| 112 | + return num/a + num/b + num/c - num/lcm(a, b) - num/lcm(a, c) - num/lcm(b, c) + num/lcm(lcm(a, b), c) |
| 113 | +} |
| 114 | + |
| 115 | +// Least common multiple |
| 116 | +func lcm(a, b int) int { |
| 117 | + // Greatest common divisor |
| 118 | + gcd := func(x, y int) int { |
| 119 | + for y != 0 { |
| 120 | + if x < y { |
| 121 | + x, y = y, x |
| 122 | + } |
| 123 | + x, y = y, x%y |
| 124 | + } |
| 125 | + return x |
| 126 | + } |
| 127 | + return a * b / gcd(a, b) |
| 128 | +} |
| 129 | +``` |
| 130 | + |
| 131 | +### **C++** |
| 132 | + |
| 133 | +<!-- 这里可写当前语言的特殊实现逻辑 --> |
74 | 134 |
|
| 135 | +```cpp |
| 136 | +class Solution { |
| 137 | +public: |
| 138 | + long gcd(long x, long y) { |
| 139 | + while (y != 0) { |
| 140 | + if (x < y) |
| 141 | + swap(x, y); |
| 142 | + long tmp = x % y; |
| 143 | + x = y; |
| 144 | + y = tmp; |
| 145 | + } |
| 146 | + return x; |
| 147 | + } |
| 148 | + |
| 149 | + long lcm(long x, long y) { return x * y / gcd(x, y); } |
| 150 | + |
| 151 | + long f(int num, int a, int b, int c) { |
| 152 | + long sumabc = long(num / a) + num / b + num / c; |
| 153 | + long intersections = long(num / lcm(a, b)) + num / lcm(a, c) + num / lcm(b, c) - num / lcm(lcm(a, b), c); |
| 154 | + return sumabc - intersections; |
| 155 | + } |
| 156 | + |
| 157 | + int nthUglyNumber(int n, int a, int b, int c) { |
| 158 | + int left = 1, right = int(2e9); |
| 159 | + while (left <= right) { |
| 160 | + int mid = left + (right - left) / 2; |
| 161 | + if (f(mid, a, b, c) < n) { |
| 162 | + left = mid + 1; |
| 163 | + } else { |
| 164 | + right = mid - 1; |
| 165 | + } |
| 166 | + } |
| 167 | + return left; |
| 168 | + } |
| 169 | +}; |
75 | 170 | ``` |
76 | 171 | |
77 | 172 | ### **...** |
|
0 commit comments