20 找出第1500个丑数

来源:互联网 发布:男性网络个人基金产品 编辑:程序博客网 时间:2024/06/05 11:42

前言

本博文部分图片, 思路来自于剑指offer 或者编程珠玑

问题描述

这里写图片描述

思路

对于这个问题, 两种思路

思路一 : 万事不能离的穷举算法, 从1开始穷举, ….是狠

思路二 : 丑数不是只由2,3,5构成的嘛,而且我们拿到的数也是由2,3,5构成的,而且是最小的10个,那么第11个一定就比前十个数中的某一个多一个因子2,或者因子3,或者因子5……也就是说,第11个丑数一定是前十个丑数中某一个丑数的2倍,或者3倍,或者5倍!![refer : http://blog.csdn.net/jinzheng069/article/details/8799009]

其实 对于书中说的 “根据丑数的性质, 一个丑数必然是另外一个丑数乘以2/ 3/ 5得到的结果“, 对于 这句话, 还懵懂了一会儿,, 但是 看了一下上面的这篇播客的这句话, 幡然醒悟啊…
根据这个思路, 我们就可以递推出各个丑数了

参考代码

/** * file name : Test14FindUglyNumber.java * created at : 5:05:23 PM Jun 8, 2015 * created by 970655147 */package com.hx.test05;public class Test14FindUglyNumber {    // 丑数问题[质因数只有2, 3, 5的数]    public static void main(String []args) {        int n = 400;        long start = System.currentTimeMillis();        findUglyNumber01(n);        findUglyNumber02(n);        findUglyNumber03(n);        long spent = System.currentTimeMillis() - start;        Log.log("spent : " + spent + " ms ..");    }    // 穷举, 找出第n个丑数,,    public static void findUglyNumber01(int n) {        int cnt = 0;        int cur = 1;        while(cnt < n) {            if(isUglyNumber(cur ++) ) {                cnt ++;            }        }        Log.log(cur-1);    }    // 递推寻找丑数, 一个丑数必然是另一个丑数的*2, *3, *5  这样依次递推, 顺序的求解每一个丑数    public static void findUglyNumber02(int n) {        int[] uglyNumbers = new int[n+1];        uglyNumbers[0] = 1;        int size = 1, cnt = 1;        int idxFor2 = findFloorFor(uglyNumbers, size, 2);        int idxFor3 = findFloorFor(uglyNumbers, size, 3);        int idxFor5 = findFloorFor(uglyNumbers, size, 5);        while(cnt < n) {            int valFor2 = uglyNumbers[idxFor2] * 2;            int valFor3 = uglyNumbers[idxFor3] * 3;            int valFor5 = uglyNumbers[idxFor5] * 5;            int min = getMin(valFor2, valFor3, valFor5);            if(min == valFor2) {                idxFor2 ++;            }            if(min == valFor3) {                idxFor3 ++;            }            if(min == valFor5) {                idxFor5 ++;            }            uglyNumbers[cnt ++] = min;//          Log.log(min);        }        Log.log(uglyNumbers[n-1]);    }    // 计算丑数, 来自剑指offer        // 没太搞懂while循环的目的啊, 似乎是为了更新各个idx, 使得该idx对应的数据*各自的基数大于当前找到的丑数[当前最大的丑数]    public static void findUglyNumber03(int n) {        int[] uglyNumbers = new int[n+1];        uglyNumbers[0] = 1;        int cnt = 1;        int idxFor2 = 0;        int idxFor3 = 0;        int idxFor5 = 0;        while(cnt < n) {            int valFor2 = uglyNumbers[idxFor2] * 2;            int valFor3 = uglyNumbers[idxFor3] * 3;            int valFor5 = uglyNumbers[idxFor5] * 5;            int min = getMin(valFor2, valFor3, valFor5);            uglyNumbers[cnt ++] = min;            while(uglyNumbers[idxFor2] * 2 <= min) {                idxFor2 ++;            }            while(uglyNumbers[idxFor3] * 3 <= min) {                idxFor3 ++;            }            while(uglyNumbers[idxFor5] * 5 <= min) {                idxFor5 ++;            }//          Log.log(min);        }        Log.log(uglyNumbers[n-1]);    }    // 获取x, y, z中较小者    private static int getMin(int valFor2, int valFor3, int valFor5) {        return getMin(valFor2, getMin(valFor3, valFor5));    }    // 获取x, y中较小者    private static int getMin(int x, int y) {        return x > y ? y : x;    }    // 找到uglyNumber乘以product中第一个大于最大的值的索引    private static int findFloorFor(int[] uglyNumbers, int cnt, int product) {        int curMax = uglyNumbers[cnt - 1];        for(int i=0; i<cnt; i++) {            if(uglyNumbers[i] * product > curMax) {                return i;            }        }        return -1;    }    // 判断一个数是不是丑数   [丑数 : 只能被2, 3, 5整除的数]    private static boolean isUglyNumber(int n) {        while ((n&1) == 0) {            n >>= 1;        }        while (n % 3 == 0) {            n /= 3;        }        while (n % 5 == 0) {            n /= 5;        }        return n == 1;    }}

效果截图

这里写图片描述

总结

对于思路二三, 使用了少量的空间存储计算所需的资源, 以及相关性质 使得计算时间大大的提高

注 : 因为作者的水平有限,必然可能出现一些bug, 所以请大家指出!

0 0
原创粉丝点击