剑指offer32_丑数_题解
丑数
题目描述
把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
示例1
输入
7
返回值
8
分析
小顶堆的方法是先存再排,dp的方法则是先排再存
方案一:小根堆
丑数是另一个丑数乘以2、3或者5的结果。
创建一个小根堆,初始时压入元素1
由于优先队列具有自动排序的功能,只要每次生成新的丑数都由堆顶元素(当前最小的丑数)乘以2、3或者5得到的,就能保证堆顶元素组成的序列即为丑数的有序序列。
代码
/**
1.时间复杂度:O(nlogn)
2.空间复杂度:O(n)
**/
class Solution
{
public:
int GetUglyNumber_Solution(int index)
{
vector<int> fac = {2, 3, 5};
priority_queue<int, vector<int>, greater<int>> q;
q.push(1);
int top = 0;
for (int i = 0; i < index; i++)
{
top = q.top();
for (const int k : fac)
{
q.push(top * k);
}
//去重
while (q.top() == top)
q.pop();
}
return top;
}
};
方案二:动态规划
参考链接
代码
/**
1.时间复杂度:O(n)
2.空间复杂度:O(n)
**/
class Solution
{
public:
int GetUglyNumber_Solution(int index)
{
int a = 0, b = 0, c = 0;
vector<int> dp(index, 0);
dp[0] = 1;//dp[i]代表第i+1个丑数
for (int i = 1; i < index; i++)
{
int n2 = dp[a] * 2, n3 = dp[b] * 3, n5 = dp[c] * 5;
dp[i] = min(min(n2, n3), n5);
//每轮计算dp[i]以后,需要更新索引a,b,c的值
// 第a个数已经通过乘2得到了一个新的丑数,那下个需要通过乘2得到一个新的丑数的数应该是第(a+1)个数
if (dp[i] == n2)
a++;
// 第 b个数已经通过乘3得到了一个新的丑数,那下个需要通过乘3得到一个新的丑数的数应该是第(b+1)个数
if (dp[i] == n3)
b++;
// 第 c个数已经通过乘5得到了一个新的丑数,那下个需要通过乘5得到一个新的丑数的数应该是第(c+1)个数
if (dp[i] == n5)
c++;
}
return dp[index - 1];
}
};