题目
Write a program to find the n-th ugly number.
Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. For example, 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 is the sequence of the first 10 ugly numbers.
Note that 1 is typically treated as an ugly number, and n does not exceed 1690.
题目分析
ugly number可以根据前面的数来计算。前面的数影响后面的数,这就是一种DP思想。
思想一
建立一个很大的布尔数组来存放每个整数是否为实数。但问题是在类当中,堆中没有那么大的位置存放。
思想二
可以将已经有的ugly number分别乘以2, 3, 5然后进行排序、去重,来获取新的一批ugly number。
但问题是,计算到1600左右的就会超时。因为,当pos = 1600时,其实代码中已经计算出了3000+的丑数,只是pos还未轮到。后来对代码进行了改进,在排序中,我们不用对num.begin() + pos进行排序,因为以前已经排好序了。这样就可以节省很多时间。
思想三
在思想二的基础上,其实可以发现,不必排序,我们按照一个升序来生成ugly number,它必定就是已经排好序的。用t2,t3,t5来记录乘以2,3,5的次数,依次加一调用。便能得到一个升序的序列。这是最优的解法,每一步都能够求出解。
源代码
//Normal
class Solution {
public:
int nthUglyNumber(int n) {
vector<long long int> num;
num.push_back(1);
int pos = 0;
while (pos < n) {
num.push_back(num[pos] * 2);
num.push_back(num[pos] * 3);
num.push_back(num[pos] * 5);
pos++;
sort(num.begin() + pos, num.end());
num.erase(unique(num.begin(), num.end()), num.end());
}
cout << num.size();
return num[n - 1];
}
};
//Advanced
class Solution {
public:
int nthUglyNumber(int n) {
if(n <= 0) return false; // get rid of corner cases
if(n == 1) return true; // base case
int t2 = 0, t3 = 0, t5 = 0; //pointers for 2, 3, 5
vector<int> k(n);
k[0] = 1;
for(int i = 1; i < n ; i ++)
{
k[i] = min(k[t2]*2,min(k[t3]*3,k[t5]*5));
if(k[i] == k[t2]*2) t2++;
if(k[i] == k[t3]*3) t3++;
if(k[i] == k[t5]*5) t5++;
}
return k[n-1];
}
};