题目
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.
翻译
求第n个丑数,丑数定义为一个数的素因子只包含2,3,5这个三个数。
分析
要求第n个素数,首先我们考虑暴力法,则对从1开始遍历,然后判断该数素因子是否是2,3,5。如果是计数加1,然后计数到n时,返回该素数即使所求。
但是暴力法时间复杂度高,而且题目限定为素因子为2,3,5所以我们是不是可以通过组合来产生有序的素数序列。
问题简化,通过素因子组合产生有序的素数序列。
下边举例分析:
1,因为1典型素数,所以第一素数为1
2,第二个素数,比1大的第一个素数。即2
3,第三个素数,可以为1*3,即3
4,第四个素数,可以有2*2,即4
5,第五个素数,可以为1*5,即5
6,第六个素数,可以为2*3,即6
我们从中寻找规律。
可以发现,无非将比当前最大的有2,3,5组成的加入素数序列中。可以对当前序列中的所有制程序2,3,5,然后求得一个最小大于最大的值。然后加入。重复计算,一直计算到第n个。
但是再对其进行仔细分析,我们发现,其中进行了一些重复计算
1,第一个,当前序列【1】,然后对其乘以2,3,5,第一个比1大的位2,将其加入。
2,第二个,当前序列为【1,2】,对其所有元素分别程序2,3,5,分别得到2,3,5;4,5,10。选择3将其加入。
3,第三个,当前序列为【1,2,3】,对其所有元素分别2,3,5,分别得到2,3,5;4,5,10;5,10,15;将4加入。
我们发现是不是加粗的在重复计算。且当计算第二个的时候,已经不用计算1*2。计算第三个的时候不用计算1*2,1*3了。
所以,我们定义三个标记序列pMulti2,pMulti3,pMulti5。
pMulit2表示,当前*pMulti2*2大于当前序列最大素数在素数序列中的元素地址。
pMulit3表示,当前*pMulti2*2大于当前序列最大素数在素数序列中的元素地址。
pMulit2表示,当前*pMulti5*5大于当前序列最大素数在素数序列中的元素地址。
然后只需要求Min(*pMulti2*2,*pMulti2*2,pMulti5*5)的最小,就是新的一个丑数。然后将其加入。
代码
class Solution {
public:
int nthUglyNumber(int n) {
if(n <= 0){
return 0;
}
int *pUglyNumber = new int[n];
pUglyNumber[0] = 1; //初始化第一个
int nextUglyIndex = 1; //记录丑数的下标
int *pMulti2 = pUglyNumber;
int *pMulti3 = pUglyNumber;
int *pMulti5 = pUglyNumber;
while(nextUglyIndex < n){
int min = Min(*pMulti2*2,*pMulti3*3,*pMulti5*5);
pUglyNumber[nextUglyIndex] = min;
while(*pMulti2*2 <= pUglyNumber[nextUglyIndex]){
++pMulti2;
}
while(*pMulti3*3 <= pUglyNumber[nextUglyIndex]){
++pMulti3;
}
while(*pMulti5*5 <= pUglyNumber[nextUglyIndex]){
++pMulti5;
}
++nextUglyIndex;
}
int ugly = pUglyNumber[n-1];
delete[] pUglyNumber;
return ugly;
}
int Min(int number1,int number2,int number3){
int min = (number1 < number2)?number1 : number2;
min = (min < number3)?min:number3;
return min;
}
};