1、题目描述 :把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
2、思路:这道题总共有两种解法,第一种解法不需要额外的空间,但时间复杂度较高。第二种,需要额外的空间,但不需要多余的计算。
首先要理解什么是丑数,第一个丑数是 1,那么判断一个数是不是丑数,只需要将数x,能整除2就除,能整除3就除,能整除5就除,保证除到最后结果是1,这个数就是丑数。
解法一:例如我们想要得到第1500个丑数,假设这个丑数是2020,那么我们要从1,2,3,4开始一直判断这期间的所有的数是不是丑数,是丑数就+1,一直判断到2020,才找到第1500个丑数。
解法二:针对上一个解法,要计算判断所有数,无论是否是丑数,都要判断,这个过程涉及到大量的多余计算。假如我们可以只计算丑数,计算到第1500个就可以了,其余的重复计算不需要。那么就要使用额外的数组空间保存已经计算出来的丑数。
丑数如何计算,可以看下规律,丑数只含有2,3,5因子,那么意味着丑数一定是使用2,3,5,乘出来的。1乘(2,3,5)得到 2,,.5;2乘(2,3,5)得到4,6,10;3乘(2,3,5)得到6,9,15,很容易发现,我们乘的话会出现重复的丑数,并且顺序是无法保证的。1,2,3,4,5,这里面的4就是由第二个丑数乘以2得到的,反而比第一个丑数乘以5还要小,可以看出丑数的顺序和第几个丑数乘以几没有强关联,有可能有一个丑数是上一轮乘法乘出来的,也可能是上上轮乘法乘出来的。因此,我们只好维护三个指针,分别是p2、p3、p5,代表分别乘2,3,5这三种乘的指针。这三个指针的快慢是不一致的分别向前乘不断的取最小值入位置即可。
3、代码:
public class Solution { public int GetUglyNumber_Solution(int index) { if(index <= 0)return 0; int p2=0,p3=0,p5=0;//初始化三个指向三个潜在成为最小丑数的位置 int[] result = new int[index]; result[0] = 1;// for(int i=1; i < index; i++){ //这里的min括号里面包含min,是由于Math.min()方法里面只能传两个参数。小改造一下 //,和直接比较三个是一个意思。 result[i] = Math.min(result[p2]*2, Math.min(result[p3]*3, result[p5]*5)); if(result[i] == result[p2]*2)p2++;//为了防止重复需要三个if都能够走到 if(result[i] == result[p3]*3)p3++;//为了防止重复需要三个if都能够走到 if(result[i] == result[p5]*5)p5++;//为了防止重复需要三个if都能够走到 } return result[index-1]; } }