/*
Write a program to find the n-th ugly number.
Ugly numbers are positive numbers whose prime factors only include 2, 3, 5.
Example:
Input: n = 10
Output: 12
Explanation: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 is the sequence of the first 10 ugly numbers.
Note:
1 is typically treated as an ugly number.
n does not exceed 1690.
*/
//每一丑数X2,X3,X5可以生成新的丑数,新的丑数也只能由此生成,
//关键点在于生成丑数的次序问题。
#include<iostream>
#include<vector>
#include<list>
#include<queue>
using namespace std;
class Solution {
public:
virtual int nthUglyNumber(int n) =0 {}
};
/*优先队列:对于每个丑数分别X2,X3,X5, push入优先队列,从优先队列中pop得到下一个丑数*/
class PriorityQueue : public Solution {
public:
int nthUglyNumber(int n) {
long long ret = 1;
vector<long long> unly({1});
priority_queue<long long,vector<long long>,greater<long long>> pq;
int index=0;
int count = 1;
while (count < n)
{
pq.push(2*unly[index]);
pq.push(3*unly[index]);
pq.push(5*unly[index]);
ret = pq.top();
while (!pq.empty() && pq.top()==ret)
pq.pop();
unly.push_back(ret);
index++;
count++;
}
return ret;
}
};
/*merge 三个有序数列:每个丑数X2,X3,X5分别加入3个有序数列,取三个数列的最小值就是新的丑数*/
class MergeQueue : public Solution {
public:
int nthUglyNumber(int n) {
long long ret = 1;
vector<list<long long>> v_list(3);
vector<long long> unly({ 1 });
int index = 0;
int count = 1;
while (count < n)
{
v_list[0].push_back(2 * unly[index]);
v_list[1].push_back(3 * unly[index]);
v_list[2].push_back(5 * unly[index]);
ret = min(min(v_list[0].front(), v_list[1].front()), v_list[2].front());
for (int i = 0; i < 3; i++)
{
if (v_list[i].front() == ret)
v_list[i].pop_front();
}
unly.push_back(ret);
count++;
index++;
}
return ret;
}
};
/*动态规划: 3指针,每个指针位置本质上相当于mergelist解法中,各有序数列的top,动态规划法一贯的优势是裁剪不需要的运算*/
class DP : public Solution {
public:
int nthUglyNumber(int n) {
long long ret = 1;
vector<long long> unly(n);
int index_m2=0;
int index_m3=0;
int index_m5=0;
int index = 0;
int count = 1;
unly[0] = 1;
for(int i=1;i<n;i++)
{
ret = min(min(2 * unly[index_m2], 3 * unly[index_m3]), 5 * unly[index_m5]);
unly[i]=ret;
if (ret == 2 * unly[index_m2])
index_m2++;
if (ret == 3 * unly[index_m3])
index_m3++;
if (ret == 5 * unly[index_m5])
index_m5++;
}
return ret;
}
};
int main()
{
Solution *solution;
int ret=0;
int n = 1600;
solution = new PriorityQueue;
ret = solution->nthUglyNumber(n);
cout << ret << endl;
solution = new MergeQueue;
ret = solution->nthUglyNumber(n);
cout << ret << endl;
solution = new DP;
ret = solution->nthUglyNumber(n);
cout << ret << endl;
return 0;
}