27
27
28
28
<!-- 这里可写通用的实现逻辑 -->
29
29
30
- 动态规划法。
30
+ ** 方法一:优先队列(最小堆) **
31
31
32
- 定义数组 dp, ` dp[i - 1] ` 表示第 i 个丑数,那么第 n 个丑数就是 ` dp[n - 1] ` 。最小的丑数是 1,所以 ` dp[0] = 1 ` 。
32
+ 初始时,将第一个丑数 $1$ 加入堆。每次取出堆顶元素 $x$,由于 $2x$, $3x$, $5x$ 也是丑数,因此将它们加入堆中。为了避免重复元素,可以用哈希表 $vis$ 去重 。
33
33
34
- 定义 3 个指针 p2,p3,p5,表示下一个丑数是当前指针指向的丑数乘以对应的质因数。初始时,三个指针的值都指向 0 。
34
+ 时间复杂度 $O(n \times \log n)$,空间复杂度 $O(n)$ 。
35
35
36
- 当 ` i∈[1,n) ` , ` dp[i] = min(dp[p2] * 2, dp[p3] * 3, dp[p5] * 5) ` ,然后分别比较 ` dp[i] ` 与 ` dp[p2] * 2 ` 、 ` dp[p3] * 3 ` 、 ` dp[p5] * 5 ` 是否相等,若是,则对应的指针加 1。
36
+ ** 方法二:动态规划 **
37
37
38
- 最后返回 ` dp[n - 1] ` 即可。
38
+ 定义数组 $dp$,其中 $dp[ i-1] $ 表示第 $i$ 个丑数,那么第 $n$ 个丑数就是 $dp[ n - 1] $。最小的丑数是 $1$,所以 $dp[ 0] =1$。
39
+
40
+ 定义 $3$ 个指针 $p_2$, $p_3$ 和 $p_5$,表示下一个丑数是当前指针指向的丑数乘以对应的质因数。初始时,三个指针的值都指向 $0$。
41
+
42
+ 当 $i$ 在 $[ 1,2..n-1] $ 范围内,我们更新 $dp[ i] =\min(dp[ p_2] \times 2, dp[ p_3] \times 3, dp[ p_5] \times 5)$,然后分别比较 $dp[ i] $ 与 $dp[ p_2] \times 2$, $dp[ p_3] \times 3$, $dp[ p_5] \times 5$ 是否相等,若是,则对应的指针加 $1$。
43
+
44
+ 最后返回 $dp[ n - 1] $ 即可。
45
+
46
+ 时间复杂度 $O(n)$,空间复杂度 $O(n)$。
39
47
40
48
<!-- tabs:start -->
41
49
42
50
### ** Python3**
43
51
44
52
<!-- 这里可写当前语言的特殊实现逻辑 -->
45
53
54
+ ``` python
55
+ class Solution :
56
+ def nthUglyNumber (self , n : int ) -> int :
57
+ h = [1 ]
58
+ vis = {1 }
59
+ ans = 1
60
+ for _ in range (n):
61
+ ans = heappop(h)
62
+ for v in [2 , 3 , 5 ]:
63
+ nxt = ans * v
64
+ if nxt not in vis:
65
+ vis.add(nxt)
66
+ heappush(h, nxt)
67
+ return ans
68
+ ```
69
+
46
70
``` python
47
71
class Solution :
48
72
def nthUglyNumber (self , n : int ) -> int :
@@ -57,13 +81,36 @@ class Solution:
57
81
p3 += 1
58
82
if dp[i] == next5:
59
83
p5 += 1
60
- return dp[n - 1 ]
84
+ return dp[- 1 ]
61
85
```
62
86
63
87
### ** Java**
64
88
65
89
<!-- 这里可写当前语言的特殊实现逻辑 -->
66
90
91
+ ``` java
92
+ class Solution {
93
+ public int nthUglyNumber (int n ) {
94
+ Set<Long > vis = new HashSet<> ();
95
+ PriorityQueue<Long > q = new PriorityQueue<> ();
96
+ int [] f = new int []{2 , 3 , 5 };
97
+ q. offer(1L );
98
+ vis. add(1L );
99
+ long ans = 0 ;
100
+ while (n-- > 0 ) {
101
+ ans = q. poll();
102
+ for (int v : f) {
103
+ long next = ans * v;
104
+ if (vis. add(next)) {
105
+ q. offer(next);
106
+ }
107
+ }
108
+ }
109
+ return (int ) ans;
110
+ }
111
+ }
112
+ ```
113
+
67
114
``` java
68
115
class Solution {
69
116
public int nthUglyNumber (int n ) {
@@ -84,6 +131,31 @@ class Solution {
84
131
85
132
### ** C++**
86
133
134
+ ``` cpp
135
+ class Solution {
136
+ public:
137
+ int nthUglyNumber(int n) {
138
+ priority_queue<long, vector<long >, greater<long >> q;
139
+ q.push(1l);
140
+ unordered_set<long > vis{{1l}};
141
+ long ans = 1;
142
+ vector<int > f = {2, 3, 5};
143
+ while (n--) {
144
+ ans = q.top();
145
+ q.pop();
146
+ for (int& v : f) {
147
+ long nxt = ans * v;
148
+ if (!vis.count(nxt)) {
149
+ vis.insert(nxt);
150
+ q.push(nxt);
151
+ }
152
+ }
153
+ }
154
+ return (int) ans;
155
+ }
156
+ };
157
+ ```
158
+
87
159
```cpp
88
160
class Solution {
89
161
public:
@@ -103,6 +175,74 @@ public:
103
175
};
104
176
```
105
177
178
+ ### ** Go**
179
+
180
+ ``` go
181
+ func nthUglyNumber (n int ) int {
182
+ h := IntHeap ([]int {1 })
183
+ heap.Init (&h)
184
+ ans := 1
185
+ vis := map [int ]bool {1 : true }
186
+ for n > 0 {
187
+ ans = heap.Pop (&h).(int )
188
+ for _ , v := range []int {2 , 3 , 5 } {
189
+ nxt := ans * v
190
+ if !vis[nxt] {
191
+ vis[nxt] = true
192
+ heap.Push (&h, nxt)
193
+ }
194
+ }
195
+ n--
196
+ }
197
+ return ans
198
+ }
199
+
200
+ type IntHeap []int
201
+
202
+ func (h IntHeap ) Len () int { return len (h) }
203
+ func (h IntHeap ) Less (i , j int ) bool { return h[i] < h[j] }
204
+ func (h IntHeap ) Swap (i , j int ) { h[i], h[j] = h[j], h[i] }
205
+ func (h *IntHeap ) Push (x interface {}) {
206
+ *h = append (*h, x.(int ))
207
+ }
208
+ func (h *IntHeap ) Pop () interface {} {
209
+ old := *h
210
+ n := len (old)
211
+ x := old[n-1 ]
212
+ *h = old[0 : n-1 ]
213
+ return x
214
+ }
215
+ ```
216
+
217
+ ``` go
218
+ func nthUglyNumber (n int ) int {
219
+ dp := make ([]int , n)
220
+ dp[0 ] = 1
221
+ p2 , p3 , p5 := 0 , 0 , 0
222
+ for i := 1 ; i < n; i++ {
223
+ next2 , next3 , next5 := dp[p2]*2 , dp[p3]*3 , dp[p5]*5
224
+ dp[i] = min (next2, min (next3, next5))
225
+ if dp[i] == next2 {
226
+ p2++
227
+ }
228
+ if dp[i] == next3 {
229
+ p3++
230
+ }
231
+ if dp[i] == next5 {
232
+ p5++
233
+ }
234
+ }
235
+ return dp[n-1 ]
236
+ }
237
+
238
+ func min (a , b int ) int {
239
+ if a < b {
240
+ return a
241
+ }
242
+ return b
243
+ }
244
+ ```
245
+
106
246
### ** JavaScript**
107
247
108
248
``` js
@@ -111,54 +251,24 @@ public:
111
251
* @return {number}
112
252
*/
113
253
var nthUglyNumber = function (n ) {
114
- const dp = [1];
254
+ let dp = [1 ];
115
255
let p2 = 0 ,
116
256
p3 = 0 ,
117
257
p5 = 0 ;
118
258
for (let i = 1 ; i < n; ++ i) {
119
259
const next2 = dp[p2] * 2 ,
120
260
next3 = dp[p3] * 3 ,
121
261
next5 = dp[p5] * 5 ;
122
- dp[i] = Math.min(next2, next3, next5);
262
+ dp[i] = Math .min (next2, Math . min ( next3, next5) );
123
263
if (dp[i] == next2) ++ p2;
124
264
if (dp[i] == next3) ++ p3;
125
265
if (dp[i] == next5) ++ p5;
266
+ dp .push (dp[i]);
126
267
}
127
268
return dp[n - 1 ];
128
269
};
129
270
```
130
271
131
- ### ** Go**
132
-
133
- ``` go
134
- func nthUglyNumber (n int ) int {
135
- dp := make ([]int , n)
136
- dp[0 ] = 1
137
- p2 , p3 , p5 := 0 , 0 , 0
138
- for i := 1 ; i < n; i++ {
139
- next2 , next3 , next5 := dp[p2]*2 , dp[p3]*3 , dp[p5]*5
140
- dp[i] = min (next2, min (next3, next5))
141
- if dp[i] == next2 {
142
- p2++
143
- }
144
- if dp[i] == next3 {
145
- p3++
146
- }
147
- if dp[i] == next5 {
148
- p5++
149
- }
150
- }
151
- return dp[n-1 ]
152
- }
153
-
154
- func min (a , b int ) int {
155
- if a < b {
156
- return a
157
- }
158
- return b
159
- }
160
- ```
161
-
162
272
### ** Rust**
163
273
164
274
``` rust
@@ -195,23 +305,20 @@ impl Solution {
195
305
``` cs
196
306
public class Solution {
197
307
public int NthUglyNumber (int n ) {
198
- if (n < 0 ) {
199
- return 0 ;
200
- }
201
- var dp = new int [n ];
308
+ int [] dp = new int [n ];
202
309
dp [0 ] = 1 ;
203
310
int p2 = 0 , p3 = 0 , p5 = 0 ;
204
- for (int i = 1 ; i < n ; i ++ ) {
311
+ for (int i = 1 ; i < n ; ++ i ) {
205
312
int next2 = dp [p2 ] * 2 , next3 = dp [p3 ] * 3 , next5 = dp [p5 ] * 5 ;
206
313
dp [i ] = Math .Min (next2 , Math .Min (next3 , next5 ));
207
314
if (dp [i ] == next2 ) {
208
- p2 += 1 ;
315
+ ++ p2 ;
209
316
}
210
317
if (dp [i ] == next3 ) {
211
- p3 += 1 ;
318
+ ++ p3 ;
212
319
}
213
320
if (dp [i ] == next5 ) {
214
- p5 += 1 ;
321
+ ++ p5 ;
215
322
}
216
323
}
217
324
return dp [n - 1 ];
0 commit comments