一.求第N个丑数
题目:我们把只包含因子2、3、5的数称作丑数(UglyNumber)。假设现在求从小到大排序的第1500个丑数。例如,6、8
都是丑数,但是14不是丑数,因为它还包括素因子7
。
解题思路一:暴力枚举法。
- 1.首先,我们应该了解什么是因子。所谓的数m是数n的因子,是指数n可以被数m整除,既
n%m=0
。 - 2.要判断一个数是不是为丑数。就要判断这个数除了能被2、3、5整除,是否可以被其他数字整除,能则不是,不能则是。也就是如果这个数可以被2整除,我们把它连续除以2;如果这个数可以被3整除,我们把它连续除以3;如果这个数可以被5整除,我们把它连续除以5。
- 3.现在我们已经知道怎么去判断一个数是否为丑数,那么要求的第1500个丑数,我们只需要从0开始遍历,如果这个数是丑数,则修改循环变量循环继续,如果不是,则直接让循环继续,总共计算1500次就可以求出来了。
代码实现:
//判断一个数是否为丑数
static int IsUglyNumber(int num)
{
while ((num % 2) == 0)
{
num /= 2;
}
while ((num % 3) == 0)
{
num /= 3;
}
while ((num % 5) == 0)
{
num /= 5;
}
return (num == 1) ? 1 : 0;
}
//求第N个丑数
int GetNUglyNum(int index)
{
if (index <= 0)
return 0;
int number = 0;
int frequecy = 0;
while (frequecy < index)
{
number++;
//如果这个数是丑数,则修改循环变量,减少一次循环次数
//如果这个数不是丑数,则不用修改循环变量,继续让numder向后枚举
if (IsUglyNumber(number) == 1)
{
frequecy++;
}
}
return number;
}
对于以上方法,当我们要求第100个丑数1536
时,计算机立刻就帮我们求出来了。但是如果我们要求第1500个丑数859963392
时,要等好长时间,也就是说这种做法效率有点低,因为它要判断每一个数直到要求的最后一个数字是不是为丑数。那我们能不能换一种思路,减少判断的次数呢?
解决思路二:
- 1.假设前面存在一个有序的丑数数组,要求下一个有序的丑数。一个丑数只能被2、3、5整除,那么说明下一个丑数必然等于前面某一个丑数乘以2、3或者5
- 2.第一个丑数必然是1,假如现在求第二个丑数并且要求和前面的丑数按照递增有序要怎么求?1*2=2,1*3=3,1*5=5,显然要有序,必然是它们中最小的那个
- 3.假设现在要求第3个丑数,1*2<3,1*3<=3,1*5=5,2*2=4,2*3=6,2*5=10,显然第3个丑数为4,但是我们发现每次都如果从1开始,有很多小于第三个丑数的值存在,我们应该在上一次求丑数的时候把这个位置记录下来,下次就可以直接求大于上一个丑数的值了。
代码实现:
//求三个值中的最小值
int Min(int n1, int n2, int n3)
{
int mid = n1 > n2 ? n2 : n1;
return mid > n3 ? n3 : mid;
}
//求第N个丑数
int GetNUglyNum_op(int index)
{
if (index <= 0)
return 0;
//开辟index个辅助空间
int *pUglyNum = (int *)malloc(sizeof(int)*index);
pUglyNum[0] = 1;//第一个丑数为1
int nextindex = 1;//下一个丑数的下标
//记录上次求丑数时大于那个丑数的位置
int *pMutiply2 = pUglyNum;
int *pMutiply3 = pUglyNum;
int *pMutiply5 = pUglyNum;
while (nextindex < index)
{
//下一个丑数是3个乘积中的最小值
int minvalue = Min(*pMutiply2 * 2, *pMutiply3 * 3, *pMutiply5 * 5);
pUglyNum[nextindex] = minvalue;
//找到小于等于有序数组中最后一个丑数的位置(避免计算比上一个丑数小的值)
while (*pMutiply2 * 2 <= pUglyNum[nextindex])
pMutiply2++;
while (*pMutiply3 * 3 <= pUglyNum[nextindex])
pMutiply3++;
while (*pMutiply5 * 5 <= pUglyNum[nextindex])
pMutiply5++;
nextindex++;
}
int nUglyNum = pUglyNum[nextindex - 1];
free(pUglyNum);
pUglyNum = NULL;
return nUglyNum;
}
上边的代码如果要求出第1500个丑数很快就可以求出来了。但是借助了1500个整型的空间,是一种空间换取时间的方法。