丑数求解以及丑数的优化

丑数:

丑数是指因子只有2,3,5的数
比如 6 因子2,3
比如 15 因子3,5
另外特别的,规定1为丑数
求第K个丑数?

最近在刷剑指offer的OJ时,在查找丑数的时候出现了超时的情况,特别记录下来优化的找法。

第一种解法:

循环数字,为丑数时index+1,直到index==k

public static void find(int index){
        ArrayList<Integer> list = new ArrayList<Integer>(index);
        int i=1;
        while(list.size()!=index){
            if(judgeUglySum(i))
                  list.add(i);
            i++;
        }
        System.out.println(list.get(list.size()-1));
    }
    /***
     * 消去所有丑数因子
     * @param i   判断i是否是丑数
     * @return
     */
    private static boolean judgeUglySum(int i) {
        while(i%2==0){
            //i/=2;
            i=i>>1; //除2 可以改为右移2
        }
        while(i%3==0){
            i/=3;
        }
        while(i%5==0){
            i/=5;
        }
        if(i==1){
            return true;
        }
        return false;
    }

这种的解法的缺点在于每次所有的数进行遍历(其中丑数只占一部分),在遍历更大都数字时会出现查找十分费时。仅仅index==1500,数字达到了8亿左右,耗时8秒;

从丑数中找丑数

下一步便是想办法从因子中找到最小的丑数
我的思维:想从因子得乘积判断最小值判断 ,发现
所以关键在于2,3,5乘什么;

      1
      1*2=2
      1*3=3
      1*5=5
      2*2=4
      2*2*2=8
      3*2  =6

解决办法是用index2,index3,index5记录上次乘的下标;

public static void find2(int index){
        if(index<0){
            return -1;
        }
        if(index<7){  // 1-6 都是丑数
            return index;
        }
        int[] array = new int[index];
        array[0]=1;
        //用于记录2,3,5乘到哪一位了
        int index2 = 0,index3 = 0,index5 = 0;

        for(int i=1;i<index;i++){
            int tmp=array[index3]*3<array[index5]*5?array[index3]*3:array[index5]*5;
            array[i]=array[index2]*2<tmp?array[index2]*2:tmp;
            if(array[i]==array[index2]*2) index2++;  //表明这次是选的2 
            if(array[i]==array[index3]*3) index3++;
            if(array[i]==array[index5]*5) index5++;
        }
        System.out.println(array[index-1]);
        //return array[index-1];
    }

改良之后算第1500个丑数的时候,零毫秒。
ps:但是会出现数字超出int范围的情况,在K=1692时丑数的时候就超出了整数的范围。
算出从1到K=1692时,总共才费时34ms,和原来的8s相比天壤之别;
这优化简直了,真的很佩服!
总结:
经过这次的练习让我觉得小的事情上还有如此多的玄机,连找个丑数这种看似很简单的问题,我最开始也没找到思路,最开始我就想在因子里面找,但是没想出来到底乘那个数字,因为最开始2最小,一直乘2也会变大。
后来开始看第一种解法,循环求余,除去因子,最后判断结果是否为1。
第二种解法,还是很巧妙的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值