Skip to content

Commit 167b4ce

Browse files
committed
feat: add solutions to lcof problem: No.49
1 parent db780ce commit 167b4ce

File tree

8 files changed

+302
-215
lines changed

8 files changed

+302
-215
lines changed

lcof/面试题49. 丑数/README.md

+154-47
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,46 @@
2727

2828
<!-- 这里可写通用的实现逻辑 -->
2929

30-
动态规划法。
30+
**方法一:优先队列(最小堆)**
3131

32-
定义数组 dp,`dp[i - 1]` 表示第 i 个丑数,那么第 n 个丑数就是 `dp[n - 1]`。最小的丑数是 1,所以 `dp[0] = 1`
32+
初始时,将第一个丑数 $1$ 加入堆。每次取出堆顶元素 $x$,由于 $2x$, $3x$, $5x$ 也是丑数,因此将它们加入堆中。为了避免重复元素,可以用哈希表 $vis$ 去重
3333

34-
定义 3 个指针 p2,p3,p5,表示下一个丑数是当前指针指向的丑数乘以对应的质因数。初始时,三个指针的值都指向 0
34+
时间复杂度 $O(n \times \log n)$,空间复杂度 $O(n)$
3535

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+
**方法二:动态规划**
3737

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)$。
3947

4048
<!-- tabs:start -->
4149

4250
### **Python3**
4351

4452
<!-- 这里可写当前语言的特殊实现逻辑 -->
4553

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+
4670
```python
4771
class Solution:
4872
def nthUglyNumber(self, n: int) -> int:
@@ -57,13 +81,36 @@ class Solution:
5781
p3 += 1
5882
if dp[i] == next5:
5983
p5 += 1
60-
return dp[n - 1]
84+
return dp[-1]
6185
```
6286

6387
### **Java**
6488

6589
<!-- 这里可写当前语言的特殊实现逻辑 -->
6690

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+
67114
```java
68115
class Solution {
69116
public int nthUglyNumber(int n) {
@@ -84,6 +131,31 @@ class Solution {
84131

85132
### **C++**
86133

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+
87159
```cpp
88160
class Solution {
89161
public:
@@ -103,6 +175,74 @@ public:
103175
};
104176
```
105177

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+
106246
### **JavaScript**
107247

108248
```js
@@ -111,54 +251,24 @@ public:
111251
* @return {number}
112252
*/
113253
var nthUglyNumber = function (n) {
114-
const dp = [1];
254+
let dp = [1];
115255
let p2 = 0,
116256
p3 = 0,
117257
p5 = 0;
118258
for (let i = 1; i < n; ++i) {
119259
const next2 = dp[p2] * 2,
120260
next3 = dp[p3] * 3,
121261
next5 = dp[p5] * 5;
122-
dp[i] = Math.min(next2, next3, next5);
262+
dp[i] = Math.min(next2, Math.min(next3, next5));
123263
if (dp[i] == next2) ++p2;
124264
if (dp[i] == next3) ++p3;
125265
if (dp[i] == next5) ++p5;
266+
dp.push(dp[i]);
126267
}
127268
return dp[n - 1];
128269
};
129270
```
130271

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-
162272
### **Rust**
163273

164274
```rust
@@ -195,23 +305,20 @@ impl Solution {
195305
```cs
196306
public class Solution {
197307
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];
202309
dp[0] = 1;
203310
int p2 = 0, p3 = 0, p5 = 0;
204-
for (int i=1; i<n; i++) {
311+
for (int i = 1; i < n; ++i) {
205312
int next2 = dp[p2] * 2, next3 = dp[p3] * 3, next5 = dp[p5] * 5;
206313
dp[i] = Math.Min(next2, Math.Min(next3, next5));
207314
if (dp[i] == next2) {
208-
p2 += 1;
315+
++p2;
209316
}
210317
if (dp[i] == next3) {
211-
p3 += 1;
318+
++p3;
212319
}
213320
if (dp[i] == next5) {
214-
p5 += 1;
321+
++p5;
215322
}
216323
}
217324
return dp[n - 1];

lcof/面试题49. 丑数/Solution.cs

+5-8
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,19 @@
11
public class Solution {
22
public int NthUglyNumber(int n) {
3-
if (n < 0) {
4-
return 0;
5-
}
6-
var dp = new int[n];
3+
int[] dp = new int[n];
74
dp[0] = 1;
85
int p2 = 0, p3 = 0, p5 = 0;
9-
for (int i=1; i<n; i++) {
6+
for (int i = 1; i < n; ++i) {
107
int next2 = dp[p2] * 2, next3 = dp[p3] * 3, next5 = dp[p5] * 5;
118
dp[i] = Math.Min(next2, Math.Min(next3, next5));
129
if (dp[i] == next2) {
13-
p2 += 1;
10+
++p2;
1411
}
1512
if (dp[i] == next3) {
16-
p3 += 1;
13+
++p3;
1714
}
1815
if (dp[i] == next5) {
19-
p5 += 1;
16+
++p5;
2017
}
2118
}
2219
return dp[n - 1];

lcof/面试题49. 丑数/Solution.go

+21-21
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
11
func nthUglyNumber(n int) int {
2-
dp := make([]int, n)
3-
dp[0] = 1
4-
p2, p3, p5 := 0, 0, 0
5-
for i := 1; i < n; i++ {
6-
next2, next3, next5 := dp[p2]*2, dp[p3]*3, dp[p5]*5
7-
dp[i] = min(next2, min(next3, next5))
8-
if dp[i] == next2 {
9-
p2++
10-
}
11-
if dp[i] == next3 {
12-
p3++
13-
}
14-
if dp[i] == next5 {
15-
p5++
16-
}
17-
}
18-
return dp[n-1]
2+
dp := make([]int, n)
3+
dp[0] = 1
4+
p2, p3, p5 := 0, 0, 0
5+
for i := 1; i < n; i++ {
6+
next2, next3, next5 := dp[p2]*2, dp[p3]*3, dp[p5]*5
7+
dp[i] = min(next2, min(next3, next5))
8+
if dp[i] == next2 {
9+
p2++
10+
}
11+
if dp[i] == next3 {
12+
p3++
13+
}
14+
if dp[i] == next5 {
15+
p5++
16+
}
17+
}
18+
return dp[n-1]
1919
}
2020

2121
func min(a, b int) int {
22-
if a < b {
23-
return a
24-
}
25-
return b
22+
if a < b {
23+
return a
24+
}
25+
return b
2626
}

lcof/面试题49. 丑数/Solution.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,19 @@
33
* @return {number}
44
*/
55
var nthUglyNumber = function (n) {
6-
const dp = [1];
6+
let dp = [1];
77
let p2 = 0,
88
p3 = 0,
99
p5 = 0;
1010
for (let i = 1; i < n; ++i) {
1111
const next2 = dp[p2] * 2,
1212
next3 = dp[p3] * 3,
1313
next5 = dp[p5] * 5;
14-
dp[i] = Math.min(next2, next3, next5);
14+
dp[i] = Math.min(next2, Math.min(next3, next5));
1515
if (dp[i] == next2) ++p2;
1616
if (dp[i] == next3) ++p3;
1717
if (dp[i] == next5) ++p5;
18+
dp.push(dp[i]);
1819
}
1920
return dp[n - 1];
2021
};

0 commit comments

Comments
 (0)