题目:
把只包含因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
(1)一个数m是另外一个数n的因子,是指n%m == 0.
丑数:假如n是丑数则 n = 2^x * 3^y * 5^z (x>=0 ,y>=0, z>=0)
方法一:遍历法
使用算法找到第index个丑数,从1开始遍历,如果是丑数则n++,知道n==index就找到第index个丑数。
丑数只含有2、3、5这三个因子,具体算法如下:
(1)如果一个数能够被2整除,那么让他继续除以2。
(2)如果一个数能够被3整除,那么让他继续除以3。
(3)如果一个数能够被5整除,那么让他继续除以5。
(4)如果这个数最后变为1 则是丑数,否则不是。
这种算法是把从1到第index个丑数中间的所有数都计算一遍,时间开销大。
方法二:创建数组保存已经找到的丑数,用空间换时间
根据丑数的定义,我们可以知道丑数都是由另一个丑数乘以2、3或者5得到的,所以我们创建一个数组,里面的数字都是排好序的,每一个前面的丑数都乘以2、3或者5得到的,关键在于怎么样让数组里的丑数是排序的。
假设数组中现在已经有若干个排好序的丑数
(1)数组的最后一个元素是这个数组中目前最大的丑数,把该数记作M;
(2)我们把现在数组中的每个丑数都乘以2,会得到一些列数,这些数有的小于M已经存在数组中了,有的大于M,但是我们需要的是这些数中第一个大于M的数。把它记为M2;
(3)把数组中的每个元素都乘以3得到的第一个大于M的数记为M3;都乘以5得到的第一个大于M的数记为M5;
(4)然后将得到M2、M3、M5做对比,最小的那个作为下一个丑数保存到数组中。
这种算法我们每次只需要遍历已经找到的丑数就可以了,而不需要遍历非丑数。开创了一个数组,占用了空间,节省了时间。
代码:
public class Solution {
public int GetUglyNumber_Solution(int index)
{
if(index <= 0)
return 0;
int[] uglyArray = new int[index];//生成容量为index的数组
uglyArray[0] = 1;//第一个丑数为1
int min = 0;//
int m2 = 0;//保存数组中所有数乘以2以后,第一个大于M的数
int m3 = 0;//保存数组中所有数乘以3以后,第一个大于M的数
int m5 = 0;//保存数组中所有数乘以5以后,第一个大于M的数
for (int i = 1; i < index; i++)
{
min = uglyArray[i];//把min 置0;
for (int j = 0; j < i; j++) //对数组中的丑数从索引为0的位置依次乘以2,第一个大于数组最后一个数的保存在m2;
{
m2 = uglyArray[j] * 2;
if(m2 > uglyArray[i-1])//一旦m2大于数组的最后一个数,则跳出当前循环,得到的m2便是第一个大于M的数
break;
}
for (int j = 0; j < i; j++)
{
m3 = uglyArray[j] * 3;
if(m3 > uglyArray[i-1])
break;
}
for (int j = 0; j < i; j++)
{
m5 = uglyArray[j] * 5;
if(m5 > uglyArray[i-1])
break;
}
//对得到的第一个大于M的m2 m3 m5进行对比 最小的那个作为数组的下一个丑数保存在数组中
if(m2 > m3)
{
min = m3;
}
else
{
min = m2;
}
if(min > m5)
min = m5;
//把此次得到的最小数保存在数组中
uglyArray[i] = min;
}
return uglyArray[index -1];
}
}