1
+ //题目链接:https://leetcode.cn/problems/chou-shu-lcof/?envType=study-plan&id=lcof
2
+ package main
3
+
4
+ import "container/heap"
5
+
6
+ //丑数的递推性质: 丑数只包含因子 2, 3, 5,因此有 “丑数 = 某较小丑数 * 某因子” (因子为 2、3、5)。
7
+ //该性质是解题的关键
8
+
9
+ //刚开始我们只拥有丑数 1,然后 经过 1 与因子 2、3、5 相乘,得到三个丑数,将该三个丑数再次与因子相乘,
10
+ //又得到部分丑数(数目无法确定,因为可能有重复出现的数字),我们不断经过此步骤,可以得到很多丑数
11
+ //
12
+ //那如何得到第 n 个呢?
13
+ //上面得到的丑数是无序的,我们可以使用动态规划得到排好序的丑数,丑数数字 dp 初始化时只有一个元素 1,三个因子的指针 p2、p3、p5 均指向 1,
14
+ //计算得到 三个因子指向的丑数 与 该因子的 乘积,取最小值,就是下一个丑数,然后找到对应的指针,将该指针自增1,指向下一个丑数,
15
+ //每次可以得到一个丑数,n-1次循环可得到第 n 个丑数。
16
+ //
17
+ //动态规划三步:
18
+ //1. 定义dp数组大小及下表含义:dp[i] 代表第 i 个丑数
19
+ //2. dp 数组状态初始化:dp[1] = 1,三个指针 p2,p3,p5=1,1,1
20
+ //3. 状态转移方程,dp[i] = min(dp[p2]*2,dp[p3]\*3,dp[p5]\*5),之后找到对应的指针,将该指针自增1
21
+
22
+ func nthUglyNumber (n int ) int {
23
+ dp := make ([]int ,n + 1 )
24
+ // dp 数组初始化,只有 1 一个丑数
25
+ dp [1 ] = 1
26
+ // 三个指针初始化指向第一个丑数
27
+ p2 ,p3 ,p5 := 1 ,1 ,1
28
+ for i := 2 ;i <= n ;i ++ {
29
+ // 寻找三个指针指向元素与对应因子乘积的最小值
30
+ num := min (dp [p2 ]* 2 ,min (dp [p3 ]* 3 ,dp [p5 ]* 5 ))
31
+ dp [i ] = num
32
+ // 找到对应指针,该指针右移(即自增1)
33
+ // 可能对应不止一个指针
34
+ if num == dp [p2 ] * 2 {
35
+ p2 ++
36
+ }
37
+ if num == dp [p3 ] * 3 {
38
+ p3 ++
39
+ }
40
+ if num == dp [p5 ] * 5 {
41
+ p5 ++
42
+ }
43
+ }
44
+ return dp [n ]
45
+ }
46
+
47
+ func min (x , y int ) int {
48
+ if x < y {
49
+ return x
50
+ }
51
+ return y
52
+ }
53
+
54
+
55
+ //此题我们还可以用小根堆来解决
56
+ //
57
+ //初始时堆为中只有第一个丑数 1 。
58
+ //
59
+ //每次取出堆顶元素 x,则 x 是堆中最小的丑数,由于 2x, 3x, 5x 也是丑数,因此将 2x, 3x, 5x 加入堆。
60
+ //
61
+ //上述做法会导致堆中出现重复元素的情况。为了避免重复元素,可以使用哈希集合去重,避免相同元素多次加入堆。
62
+ //
63
+ //在排除重复元素的情况下,第 n 次从最小堆中取出的元素即为第 n 个丑数。
64
+
65
+ type maxH []int
66
+
67
+ func (this maxH ) Len () int { return len (this )}
68
+ func (this maxH ) Less (i ,j int ) bool {
69
+ return this [i ] < this [j ]
70
+ }
71
+ func (this maxH ) Swap (i ,j int ){
72
+ this [i ],this [j ] = this [j ],this [i ]
73
+ }
74
+ func (this * maxH ) Push (v interface {}){
75
+ * this = append (* this ,v .(int ))
76
+ }
77
+ func (this * maxH ) Pop () interface {}{
78
+ old := * this
79
+ n := len (old )
80
+ res := old [n - 1 ]
81
+ * this = old [:n - 1 ]
82
+ return res
83
+ }
84
+
85
+
86
+ func nthUglyNumber_2 (n int ) int {
87
+ uglys := & maxH {1 }
88
+ factors := []int {2 ,3 ,5 }
89
+ record := map [int ]struct {}{}
90
+ record [1 ] = struct {}{}
91
+ for i := 1 ;;i ++ {
92
+ num := heap .Pop (uglys ).(int )
93
+ if i == n {
94
+ return num
95
+ }
96
+ for _ ,f := range factors {
97
+ next := num * f
98
+ if _ ,has := record [next ];! has {
99
+ heap .Push (uglys ,next )
100
+ record [next ] = struct {}{}
101
+ }
102
+ }
103
+ }
104
+ }
0 commit comments