算法:第n个丑数-java

题目

求第n个丑数

丑数定义

  • 1是丑数
  • 只包含质因子2,3和5的数称作丑数。如8,6,15

算法思路

一个丑数(除1外)是排在它前边的某个丑数乘以2或者乘以3或者乘以5得到的,那么我们只要在当前得到的丑数集合中找到比当前集合中最大丑数刚刚好大的丑数即可,因为我们要保持有序,才好找到第N个丑数,现在难点是怎么在O(1)时间内就找到一个丑数,使得它乘以2或者乘以3或者乘以5刚刚好大于当前最大丑数呢?

我们设置三个游标:

  • 一个表示所指丑数乘以2是下一个可能加入到丑数集合中的丑数
  • 一个表示所指丑数乘以3是下一个可能加入到丑数集合中的丑数
  • 一个表示所指丑数乘以5是下一个可能加入到丑数集合中的丑数

当我们找到这三个游标,然后分别对应乘以2,3,5后,再比较,拿出最小的那个就是要插入当前丑数集合的丑数。而这三个游标的更新标准是,若当前的游标乘以对应数,大于刚加入的丑数,则不要变,否则就加1.

代码实现

public class UglyNum {

    private static final int[] times = new int[]{2,3,5};
    /**
      查第n个丑数
      丑数定义:只能被2、3、5整除的数。
      */
    public static int solution(int n) {
        int[] uglyNumHolder = new int[n];
        init(uglyNumHolder);
        if (n <= 5) {
            System.out.println(uglyNumHolder[n-1]);

            return uglyNumHolder[n-1];
        }
        int[] minIndexHolder = new int[]{0,0,0};// 0位记录最小2的index,1位记录最小3的index,2位记录最小5的index
        for (int currentCount = 5;currentCount < n; currentCount++) {
            for (int i=0; i<3; i++) {
                while(uglyNumHolder[minIndexHolder[i]] * times[i] <= uglyNumHolder[currentCount - 1] || minIndexHolder[i] >= n) {
                    minIndexHolder[i] = minIndexHolder[i] + 1;
                }
            }
            uglyNumHolder[currentCount] = min(uglyNumHolder[minIndexHolder[0]] * times[0],
                                                uglyNumHolder[minIndexHolder[1]] * times[1],
                                                uglyNumHolder[minIndexHolder[2]] * times[2]);
            
        }
        System.out.println(uglyNumHolder[n-1]);
        return uglyNumHolder[n-1];
    }
    private static int min(int a,int b,int c) {
        int min = a;
        if (b < min) {
            min = b;
        }
        if (c < min) {
            min = c;
        }
        return min;
    }
    public static void main(String[] args) {
        solution(10);
        solution(100);
        solution(1000);
        solution(1500);
    }
    /** 初始化前五个数 */
    private static void init(int[] uglyNumHolder) {
        for (int i=0; i< (uglyNumHolder.length > 5 ? 5 : uglyNumHolder.length); i++) {
            uglyNumHolder[i] = i+1;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值