丑数

丑数的定义:丑数分解因子中只能有2,3,5,不能有其他数字。根据定义可知一个丑数是另外一个丑数乘以2,或3,或5得到的。第一个丑数为1.

本题的要求,输入一个正整数n,要求得到按升序排列的第n个丑数

public int getUglyNumber() {}

首先我们用最容易想到的解题方法:从1开始一个一个数判断,并用计数器累计目前的丑数序号,直至计数器为n,返回该数。

判断一个数是否为丑数:因为丑数由一系列2,3,5相乘得到,故我们可以让num一直除以2,3,5,若最后num==1,则该数是丑数。

public boolean isUglyNumber(int num) {
        while (num % 2 == 0) {
            num = num / 2;
        }
        while (num % 3 == 0) {
            num = num / 3;
        }
        while (num % 5 == 0) {
            num = num / 5;
        }
        if (num == 1) return true;
        else return false;

然后采用逐个判断的方式,得到第n个丑数:

 

public int getUglyNumber(int targetIndex) {
        int count = 0, num = 0;
        while (count != targetIndex) {
            if (isUglyNumber(num)) count++;
            num++;
        }
        return num;
    }

 

上面的解题方法理论上可行,但是面试是100%不会通过的,接下来讲解比较合理的方法。

根据上述可知,丑数都是由第一个丑数1乘以2,3,5得到的,那我们无须根据num++来一个个判断num是不是丑数,可以直接根据前面的丑数乘以2,3,5得到新的丑数。关键问题是,得到新的丑数之后,我们怎么知道它们的顺序问题,因为要求返回的是升序的第n个丑数。

每次得到新丑数有三种方式:a✖2,b✖3,c✖5,我们可以根据Math.Min(Math.min(a✖2,b✖3),c✖5)得到下一个丑数。a,b,c的选取很关键,因为num之前的所有丑数都可以当作a,b,c,但是这样选取会增加计算量,如果我们每次计算新丑数时,可以直接确定a,b,c那简直perfect。

最理想的状态是\[\left\{ \begin{array}{l}
{a_i} \times 2 > num > {a_{i - 1}} \times 2\\
{b_i} \times 3 > num > {b_{i - 1}} \times 3\\
{a_i} \times 5 > num > {a_{i - 1}} \times 5
\end{array} \right.\]

即刚好限制a,b,c,让他们分别乘2,3,5后的丑数刚好大于当前丑数num,刚好的意思时此处的a,b,c前面的a', b', c' 乘以2, 3, 5后还是小于num的。下面时具体的实现代码:

 public int getUglyNumber(int targetIndex) {
        int[] dp = new int[targetIndex];
        int a = 0, b = 0, c = 0;
        for (int i = 1; i < dp.length; i++) {
            dp[i] = Math.min(Math.min(a * 2, b * 3), c * 5);
            if (dp[i] == a * 2) a++;
            if (dp[i] == b * 3) b++;
            if (dp[i] == c * 5) c++;
        }
        return dp[targetIndex - 1];
    }

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值