题目要求
把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
解题分析
首先我们能想到的方法就是,循环遍历,对每一个数字进行判断,如果是丑数那么数量加一,直到等于N的时候,返回。但是如此计算有一个很大的问题就是,每一个数字都需要计算一次,即使这个数不是丑数,所以计算消耗非常大,是不会通过要求的。
有没有只需要计算丑数的方法?
答案是肯定的,我们可以发现一个规律,如果p是丑数,那么根据题目可以知道
p
=
2
x
∗
3
y
∗
5
z
p=2^x * 3^y * 5^z
p=2x∗3y∗5z换句话说我们只要赋予x,y,z不同的值就可以得到不同的丑数,那么如果要根据顺序找出丑数我们需要怎么办呢? 根据丑数具有的性质,我们已知1是第一个丑数,那么可以把1分别乘上2,3,5然后在乘积中选出最小的作为第2个丑数。然后我们再对刚新加的丑数(2)分别乘上2,3,5 然后在乘积中(包括前一步1乘,3,5的结果)选出最小的作为第3个丑数,依次类推。
这里边有一个细节需要注意,设有丑数p<q, 那么得到2p<2q,那么“我”在前面比你小的数都没被选上,你后面生成新的丑数一定比“我”大吧,那么你乘2生成的丑数一定比我乘2的大吧,那么在我选上之后你才有机会选上。
其实每次我们只用比较3个数:用于乘2的最小的数、用于乘3的最小的数,用于乘5的最小的数。也就是比较(2x , 3y, 5z) ,x>=y>=z的
简而言之,我们就是根据已知算出一个结果,然后把结果作为已知去算下一个结果,逐次计算即可。题目有点烧脑,但是代码写起来还是很好理解!可以画图辅助理解!
主要代码c++
class Solution {
public:
int GetUglyNumber_Solution(int index) {
if(index<7) return index;
vector<int> result(index);
int t2=0,t3=0,t5=0,i;
result[0] = 1; //第一个丑数 1
for(i=1;i<index;++i)
{
result[i] = min(result[t2]*2,min(result[t3]*3,result[t5]*5));
if(result[i] == result[t2]*2) ++t2;
if(result[i] == result[t3]*3) ++t3;
if(result[i] == result[t5]*5) ++t5;
}
return result[index - 1];
}
};