九度OJ-题目1214:丑数

题目链接地址:

九度OJ-题目1214:丑数


题目描述:
把只包含因子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
****************************************************************/


猜你喜欢

转载自blog.csdn.net/pengyan0812/article/details/46439983