题目描述
给你一个整数 n
,请你找出并返回第 n
个 丑数 。
丑数 就是质因子只包含 2
、3
和 5
的正整数。
示例 1:
输入:n = 10 输出:12 解释:[1, 2, 3, 4, 5, 6, 8, 9, 10, 12] 是由前 10 个丑数组成的序列。
示例 2:
输入:n = 1 输出:1 解释:1 通常被视为丑数。
提示:
1 <= n <= 1690
解题思路
class Solution {
public:
int nthUglyNumber(int n) {
// 小顶堆+集合去从
priority_queue<long long, vector<long long>, greater<long long>> pq;
unordered_set<long long> uniset;
pq.push(1);
while (--n) {
auto u = pq.top();
pq.pop();
if (!uniset.count(2 * u)) {
uniset.insert(2 * u);
pq.push(2 * u);
}
if (!uniset.count(3 * u)) {
uniset.insert(3 * u);
pq.push(3 * u);
}
if (!uniset.count(5 * u)) {
uniset.insert(5 * u);
pq.push(5 * u);
}
}
return pq.top();
}
};
采用了小顶堆(优先队列)和集合(哈希表)的组合来实现。基本思路是从最小的丑数开始(即 1),通过乘以 2、3、5 来生成新的丑数,并使用优先队列来保持丑数的排序,同时用集合来避免重复计算相同的丑数。
以下是详细的解析:
初始化:
- 使用
priority_queue<long long, vector<long long>, greater<long long>>
来创建一个小顶堆,这里的greater
是使堆成为最小堆,即堆顶是最小元素。 - 使用
unordered_set<long long>
来记录已经生成的丑数,防止重复计算。
生成丑数:
- 将 1 作为第一个丑数推入小顶堆和集合中。
- 进行循环,每次循环找到当前堆顶的丑数(即当前最小的丑数),并将其从堆中弹出。
- 使用当前丑数生成新的丑数(乘以 2、3、5),并检查新生成的丑数是否已存在于集合中:
- 如果不存在,将其加入集合和堆中。
- 循环
n-1
次(因为第一次已经包括了丑数 1),最后堆顶的元素就是第n
个丑数。
返回结果:
- 在循环结束后,堆顶元素是第
n
个丑数,将其返回。
代码优点
- 效率:通过小顶堆维护丑数的顺序,可以快速获取下一个最小丑数,保证了算法的效率。
- 去重:使用哈希集合有效避免了生成重复的丑数,节约了空间和时间。