题目链接地址:
题目描述:
把只包含因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含因子7。
习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
输入:
输入包括一个整数N(1<=N<=1500)。
输出:
可能有多组测试数据,对于每组数据,
输出第N个丑数。
样例输入:
3
样例输出:
3
解题思路:
这道题我的想法是从2开始依次遍历每个整数,如果某个整数只包含因子2、3和5,就可以认为它是丑数,这个方法显然太暴力了,肯定会超时的。于是上网搜了一下此题的解法,发现网上的解法都大致一样:因为除1之外,后面的丑数都只包含2,3,5这3个因子,可以由2,3,5这3个因子与已有的丑数相乘推算出新的丑数。以下是推算的具体过程:
(1) 根据3个因子将候选丑数分成3类:由与2相乘得到的候选丑数,由与3相乘得到的候选丑数,由与5相乘得到的候选丑数;
(2) 每次都从这3类候选丑数中选择一个最小值做为新的丑数,并且更新相应类的候选丑数。
举个栗子,以下是求第7个丑数的过程:
1) 第1个丑数是1;
2) 将2,3,5分别与第1个丑数1相乘,此时候选丑数是{2,3,5},所以第2个丑数是2,此时丑数序列为[1,2];
3) 将2与第2个丑数2相乘得4;3,5分别与第1个丑数1相乘,此时候选丑数是{4,3,5},所以第3个丑数是3,
此时丑数序列为[1,2,3];
4) 将2与第2个丑数2相乘得4,将3与第2个丑数2相乘得6,将5与第1个丑数1相乘得5,此时候选丑数是{4,6,5},
所以第4个丑数是4,此时丑数序列为[1,2,3,4];
5) 将2与第3个丑数3相乘得6,将3与第2个丑数2相乘得6,将5与第1个丑数1相乘得5,此时候选丑数是{6,6,5},
所以第5个丑数是5,此时丑数序列为[1,2,3,4,5];
6) 将2与第3个丑数3相乘得6,将3与第2个丑数2相乘得6,将5与第2个丑数2相乘得10,此时候选丑数是{6,6,10},
所以第6个丑数是6,此时丑数序列为[1,2,3,4,5,6];
7) 将2与第4个丑数4相乘得8,将3与第3个丑数3相乘得9,将5与第2个丑数2相乘得10,此时候选丑数是{8,9,10},
所以第7个丑数是8,此时丑数序列为[1,2,3,4,5,6,8]。
AC代码如下:
#include<stdio.h>
#define MAX 1501
/**
* 返回3个数中的最小值
* @param long long a 第一个数
* @param long long b 第二个数
* @param long long c 第三个数
* @return long long 三个数中的最小值
*/
long long getMinOfThreeNumbers(long long a,long long b,long long c)
{
long long min = a;
if(b < min)
min = b;
if(c < min)
min = c;
return min;
}
/**
* 获取前n个丑数
* @param longlong uglyNumber[] 用于存放丑数的数组
* @return void;
*/
void getUglyNumbers(long long uglyNumber[],int n)
{
int i;
int indexOfUglyNumber = 1; // 丑数数组对应的下标
int indexOfTwo = 1; // 与2对应的乘数的在丑数数组中的下标
int indexOfThree = 1; // 与3对应的乘数的在丑数数组中的下标
int indexOfFive = 1; // 与5对应的乘数的在丑数数组中的下标
long long curUglyNumber; // 当前生成的丑数
long long curUglyNumberOfTwo; // 由与2相乘得到的丑数
long long curUglyNumberOfThreee; // 由与3相乘得到的丑数
long long curUglyNumberOfFive; // 由与5相乘得到的丑数
uglyNumber[1] = 1; // 第1个丑数是1
for(i = 2;i <= 1500; i++)
{
curUglyNumberOfTwo = 2 * uglyNumber[indexOfTwo];
curUglyNumberOfThreee = 3 * uglyNumber[indexOfThree];
curUglyNumberOfFive = 5 * uglyNumber[indexOfFive];
// 从当前3个候选中,选择最小的一个做为新的丑数
curUglyNumber = getMinOfThreeNumbers(curUglyNumberOfTwo,curUglyNumberOfThreee,curUglyNumberOfFive);
uglyNumber[++indexOfUglyNumber] = curUglyNumber;
// 更新各个乘数的下标
while(2 * uglyNumber[indexOfTwo] <= curUglyNumber)
{
indexOfTwo++;
}
while(3 * uglyNumber[indexOfThree] <= curUglyNumber)
{
indexOfThree++;
}
while(5 * uglyNumber[indexOfFive] <= curUglyNumber)
{
indexOfFive++;
}
}
}
/**
* 打印第n个丑数
* @param long long uglyNumber[] 存储丑数的数组
* @param int n n表示打印第n个丑数
* @return void
*/
void printNthUglyNumber(long long uglyNumber[],int n)
{
printf("%lld\n",uglyNumber[n]);
}
int main()
{
long long uglyNumber[MAX]; // 存放丑数
int n;
getUglyNumbers(uglyNumber,1500); // 获取前1500个丑数
while(EOF != scanf("%d",&n))
{
printNthUglyNumber(uglyNumber,n);
}
return 0;
}
/**************************************************************
Problem: 1214
User: blueshell
Language: C++
Result: Accepted
Time:10 ms
Memory:1020 kb
****************************************************************/