面试题: 丑数
题目:
我们把只包含因子2、3和5的数称作丑数(Ugly Number)。
求按从小到大的顺序的第1500个丑数。
例如6、8都是丑数,但14不是,因为它包含因子7。习惯上我们把1当做第一个丑数
思路:
参考:https://blog.csdn.net/Tianzez/article/details/80385144
“以空间换时间”
根据丑数的定义,一个丑数肯定是另一个丑数乘以2、3或5的结果(丑数1除外)。
创建一个数组,里面存放的是已经排序好的丑数,每个丑数是前面某个丑数乘以2、3或5放入结果。把数组中现有的最大丑数记做M
要得到的下一个丑数,肯定是前面某一个丑数乘以2、3或者5(定义)
1. 首先考虑把已有的每个丑数乘以2。在乘以2的时候,能得到若干个结果:
对于小于或者等于M的值,此时肯定已经在数组中了,不再考虑;
对于大于M的结果,只需要第一个大于M的结果,因为生成时是按从小到大顺序生成的,更大的结果以后再考虑
把得到的第一个乘以2后大于M的结果,记为M2,同样把已有的每一个丑数乘以3和5,能得到第一个大于M的结果M3和M5,下一个丑数应该是M2、M3和M5三个数的最小者
2. 实际时,并不需要把已有的每个丑数分别乘以2、3和5,因为已有的丑数是按顺序存放在数组中的。
对于乘以2而言,M前面一定存在某个丑数x,x前面的所有丑数乘以2的结果都小于M;x后面的所有丑数乘以2的结果都大于M。只要记住x这个丑数的位置,同时每次生成新的丑数时再去更新x的位置即可。对于3、5而言同理。
每次更新现有最大丑数M后,对2、3、5的每个记录位置m2loc,m3loc,m5loc分别更新:对m2loc位置的丑数×2,如果小于当前M,则将m2loc++,移动到下一个更大的丑数位置,再计算m2loc位置的丑数×2,直到其结果超过M为止;更新m3loc和m5loc同理
代码:
public class Q49 {
public static void main(String[] args) {
System.out.print(amethod(1500));
}
public static int amethod(int x) {
if(x<1)
return 0;
if(x==1)
return 1;
int[] list = new int[x];
list[0]=1;
int count = 1;
int m2loc = 0;
int m3loc = 0;
int m5loc = 0;
while(count<x) {
list[count] = min(list[m2loc]*2,list[m3loc]*3,list[m5loc]*5);
while(list[m2loc]*2<=list[count])
m2loc++;
while(list[m3loc]*3<=list[count])
m3loc++;
while(list[m5loc]*5<=list[count])
m5loc++;
System.out.printf("count:%d\t%d\n",count,list[count]);
count++;
}
return list[x-1];
}
public static int min(int a,int b,int c) {
int temp = (b<c)?b:c;
int re = (temp<a)?temp:a;
return re;
}
}