剑指 Offer 49. 丑数
我们把只包含质因子 2、3 和 5 的数称作丑数(Ugly Number)。求按从小到大的顺序的第 n 个丑数。
示例:
输入: n = 10
输出: 12
解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。
说明:
1 是丑数。
n 不超过1690。
解析:
方法1:优先队列思想,map去重
从丑数1开始算起,分别乘以2,3,5,然后将结果放入优先队列中,采用map去重,每次取最小的丑数分别再乘以2,3,5,一直计算下去,直到得到第n个丑数为止
var dp [1700]int
func nthUglyNumber(n int) int {
dp[1]=1
if dp[n]!=0{
return dp[n]
}
count:=1
index:=1
aMap:=make(map[int]int)
for count<n{
aMap[index*2]=1
aMap[index*3]=1
aMap[index*5]=1
minKey:=index*2
for key:= range aMap{
if key<minKey{
minKey=key
}
}
index=minKey
count++
delete(aMap,index)
}
dp[n]=index
return index
}
方法2:三指针法
核心思想:每个丑数都是其他丑数或乘以2,或乘以3,或乘以5得到的,同理,每个丑数都需要乘以2,乘以3,乘以5,来得到其他的丑数,那可以有三个指针,p2,p3,p5
p2:指向还未乘以2的丑数的位置
p3:指向还未乘以3的丑数的位置
p5:指向还未乘以5的丑数的位置
那么可以得到状态转移方程
dp[i]=min(dp[p2],dp[p3],dp[p5])
看看当前dp[i]是由那个指针得到的,将那个指针向前移动一位即可
注意重复的情况,有的时候,同一个丑数可以由两个不同的指针得到,比如6,可以是32,也可以是23,这个时候,p2,p3指针都应该移动
时间复杂度:O(N)
空间复杂度:O(N)
var dp [1700]int
func Min(a,b,c int) int{
minValue:=a
if minValue>b{
minValue=b
}
if minValue>c{
minValue=c
}
return minValue
}
func nthUglyNumber(n int) int {
if dp[n]!=0{
return dp[n]
}
dp[1]=1
p2,p3,p5:=1,1,1
for i:=2;i<=n;i++{
a:=dp[p2]*2
b:=dp[p3]*3
c:=dp[p5]*5
dp[i]=Min(a,b,c)
if dp[i]==a{
p2++
}
if dp[i]==b{
p3++
}
if dp[i]==c {
p5++
}
}
return dp[n]
}