丑数java_Java 实现丑数

把只包含因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。

代码

解法一

所谓一个数m是另一个数n的因子,是指n能被m整除,也就是说n%m==0.

public static int[] findUglyNumbers(int n) {

if (n <= 0) {

return null;

}

int[] result = new int[n];

result[0] = 1;

int index = 1;

int calNumber = 1;

while (index < n) {

calNumber++;

// 是不是丑数都要计算一次

if (isUglyNumber(calNumber)) {

result[index] = calNumber;

index++;

}

}

return result;

}

/**

* 判断一个数是否是丑数,即只包含因子2,3,5的数,即

* 如果可以被2整除,就连续除以2,直到不能被2整除为止

* 如果可以被3整除,就连续除以3,直到不能被3整除为止

* 如果可以被5整除,就连续除以5,直到不能被5整除为止

* 如果最后的结果是1,说明是丑数,否则不是

* 例如,30,可以被2整除,然后除以2得到15

* 15,可以被3整除,然后除以3得到5

* 5,可以被5整除,然后除以5得到1

* @param n

* @return

*/

private static boolean isUglyNumber(int n) {

while (n % 2 == 0) {

n /= 2;

}

while (n % 3 == 0) {

n /= 3;

}

while (n % 5 == 0) {

n /= 5;

}

return n == 1;

}

解法二

只计算丑数,而不计算非丑数。丑数=丑数*(2/3/5),所以创建数组保存有序的丑数。关键在于如何在计算丑数的过程中保持数组有序。当前的丑数必然是之前某一个丑数*因子的结果,但是不需要每个数都要乘一遍2、3、5。要获得的丑数必然是大于现在已有的,在计算得出丑数中选择一个最小的放入数组中,来保持数组的有序,因为新放入的丑数是根据之前的丑数计算得到的,所以必然是有序的。为了每次新得到的三个丑数都是比已有丑数大,且最小,所以要记录各个因子下次计算要使用的已有丑数在什么位置,否则就会出现跳数,比如已有{1,2,3,4},我们知道下一个丑数应该是5,但是如果因子5没有选择第一个丑数1来相乘,就会漏掉5这个丑数。

public static int[] findUglyNumbers2(int n) {

if (n <= 0) {

return null;

}

int[] result = new int[n];

// 1作为第一个丑数

result[0] = 1;

// 初始2,3,5因子对应的乘数为第一个丑数,即1

int divisor2 = 0;

int divisor3 = 0;

int divisor5 = 0;

// result={1}

// result[divisor2=0]=1, result[divisor3=0]=1, result[divisor5=0]=1, multiply2=2, multiply3=3, multiply5=5

// min = multiply2,所以 此时divisor2=1, divisor3=0, divisor5=0

// result={1, 2}

// result[divisor2=1]=2, result[divisor3=0]=1, result[divisor5=0]=1, multiply2=4, multiply3=3, multiply5=5

// min = multiply3,所以 此时divisor2=1, divisor3=1, divisor5=0

// result={1, 2, 3}

// result[divisor2=1]=2, result[divisor3=1]=2, result[divisor5=0]=1, multiply2=4, multiply3=6, multiply5=5

// min = multiply2,所以 此时divisor2=3, divisor3=1, divisor5=0

// result={1, 2, 3, 4}

// result[divisor2=3]=4, result[divisor3=1]=2, result[divisor5=0]=1, multiply2=8, multiply3=6, multiply5=5

// min = multiply5,所以 此时divisor2=3, divisor3=2, divisor5=1

// result={1, 2, 3, 4, 5}

// result[divisor2=3]=4, result[divisor3=2]=3, result[divisor5=1]=2, multiply2=8, multiply3=6, multiply5=10

// min = multiply3,所以 此时divisor2=3, divisor3=3, divisor5=1

// result={1, 2, 3, 4, 5, 6}

for (int i = 1; i < n ; i++) {

// 根据因子对应的乘数下表计算得出下一个丑数

int multiply2 = result[divisor2] * 2;

int multiply3 = result[divisor3] * 3;

int multiply5 = result[divisor5] * 5;

// 找出三个因子乘以上一个对应丑数后最小的那个丑数,以此来保证丑数有序

int min = Math.min(multiply2, Math.min(multiply3, multiply5));

// 将最小的丑数放入结果集中,用于下一次计算

result[i] = min;

// 找出对应此次计算最小丑数的因子,并移动指针指向下一次计算薪丑数对应的老丑数下标

if (multiply2 == result[i]) {

divisor2++;

}

if (multiply3 == result[i]) {

divisor3++;

}

if (multiply5 == result[i]) {

divisor5++;

}

}

return result;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值