• 【剑指Offer学习】【面试题34:丑数】


    题目:我们把仅仅包括因子2、3 和5 的数称作丑数(Ugly Number)。求从小到大的顺序的第1500个丑数。


    举例说明:

    比如6、8 都是丑数。但14 不是。它包括因子7。习惯上我们把1 当做第一个丑数。

    解题思路:

    第一种:逐个推断每个数字是不是丑数的解法,直观但不够高效。

    另外一种:创建数组保存已经找到丑数,用空间换时间的解法。

    依据丑数的定义。 丑数应该是还有一个丑数乘以2、3 或者5 的结果(1除外)。

    因此我们能够创建一个数组,里面的数字是排好序的丑数,每个丑数都是前面的丑数乘以2、3或者5得到的。

    这样的思路的关键在于如何确保数组里面的丑数是排好序的。

    如果数组中已经有若干个丑数排好序后存放在数组中。而且把己有最大的丑数记做M,我们接下来分析如何生成下一个丑数。该丑数肯定是前面某一个丑数乘以2、3 或者5 的结果, 所以我们首先考虑把已有的每个丑数乘以2。在乘以2 的时钝能得到若干个小于或等于M 的结果。由于是依照顺序生成的,小于或者等于M 肯定己经在数组中了。我们不需再次考虑:还会得到若干个大于M 的结果,但我们仅仅须要第一个大于M 的结果。由于我们希望丑数是按从小到大的顺序生成的,其它更大的结果以后再说。

    我们把得到的第一个乘以2 后大于M 的结果记为M2,相同,我们把已有的每个丑数乘以3 和5。能得到第一个大于M 的结果M3 和M,那么下一个丑数应该是M2、M3 和M5这3个数的最小者。

    前面分析的时候,提到把已有的每个丑数分别都乘以2、3 和5。

    其实这不是必须的,由于已有的丑数是按顺序存放在数组中的。对乘以2而言。 肯定存在某一个丑数T2,排在它之前的每个丑数乘以2 得到的结果都会小于已有最大的丑数,在它之后的每个丑数乘以2 得到的结果都会太大。我们仅仅需记下这个丑数的位置, 同一时候每次生成新的丑数的时候,去更新这个T2。对乘以3 和5 而言。 也存在着相同的T3和T5。

    本题实现了两种方法

    代码实现:

    public class Test34 {
        /**
         * 推断一个数是否仅仅有2,3。5因子(丑数)
         *
         * @param num 待推断的数,非负
         * @return true是丑数。false丑数
         */
        private static boolean isUgly(int num) {
            while (num % 2 == 0) {
                num /= 2;
            }
    
            while (num % 3 == 0) {
                num /= 3;
            }
    
            while (num % 5 == 0) {
                num /= 5;
            }
    
            return num == 1;
        }
    
        /**
         * 找第index个丑数,速度太慢
         *
         * @param index 第index个丑数
         * @return 相应的丑数值
         */
        public static int getUglyNumber(int index) {
            if (index <= 0) {
                return 0;
            }
    
            int num = 0;
            int uglyFound = 0;
            while (uglyFound < index) {
                num++;
                if (isUgly(num)) {
                    ++uglyFound;
                }
            }
    
            return num;
        }
    
        /**
         * 找第index个丑数。【另外一种方法】
         *
         * @param index 第index个丑数
         * @return 相应的丑数值
         */
        public static int getUglyNumber2(int index) {
            if (index <= 0) {
                return 0;
            }
    
            int[] pUglyNumbers = new int[index];
            pUglyNumbers[0] = 1;
            int nextUglyIndex = 1;
    
            int p2 = 0;
            int p3 = 0;
            int p5 = 0;
    
            while (nextUglyIndex < index) {
                int min = min(pUglyNumbers[p2] * 2, pUglyNumbers[p3] * 3, pUglyNumbers[p5] * 5);
                pUglyNumbers[nextUglyIndex] = min;
    
                while (pUglyNumbers[p2] * 2 <= pUglyNumbers[nextUglyIndex]) {
                    p2++;
                }
    
                while (pUglyNumbers[p3] * 3 <= pUglyNumbers[nextUglyIndex]) {
                    p3++;
                }
    
                while (pUglyNumbers[p5] * 5 <= pUglyNumbers[nextUglyIndex]) {
                    p5++;
                }
    
                nextUglyIndex++;
            }
    
            return pUglyNumbers[nextUglyIndex - 1];
        }
    
        private static int min(int n1, int n2, int n3) {
            int min = n1 < n2 ? n1 : n2;
            return min < n3 ?

    min : n3; } public static void main(String[] args) { System.out.println("Solution 1:"); test1(); System.out.println(); System.out.println("Solution 2:"); test2(); } private static void test1() { System.out.println(getUglyNumber(1)); // 1 System.out.println(getUglyNumber(2)); // 2 System.out.println(getUglyNumber(3)); // 3 System.out.println(getUglyNumber(4)); // 4 System.out.println(getUglyNumber(5)); // 5 System.out.println(getUglyNumber(6)); // 6 System.out.println(getUglyNumber(7)); // 8 System.out.println(getUglyNumber(8)); // 9 System.out.println(getUglyNumber(9)); // 10 System.out.println(getUglyNumber(10)); // 12 System.out.println(getUglyNumber(11)); // 15 System.out.println(getUglyNumber(1500)); // 859963392 System.out.println(getUglyNumber(0)); // 0 } private static void test2() { System.out.println(getUglyNumber2(1)); // 1 System.out.println(getUglyNumber2(2)); // 2 System.out.println(getUglyNumber2(3)); // 3 System.out.println(getUglyNumber2(4)); // 4 System.out.println(getUglyNumber2(5)); // 5 System.out.println(getUglyNumber2(6)); // 6 System.out.println(getUglyNumber2(7)); // 8 System.out.println(getUglyNumber2(8)); // 9 System.out.println(getUglyNumber2(9)); // 10 System.out.println(getUglyNumber2(10)); // 12 System.out.println(getUglyNumber2(11)); // 15 System.out.println(getUglyNumber2(1500)); // 859963392 System.out.println(getUglyNumber2(0)); // 0 } }

    执行结果:

    这里写图片描写叙述

  • 相关阅读:
    Knowing how all your components work together: distributed tracing with Zipkin
    Java Annotation Processors
    深度剖析JDK动态代理机制
    Java 代理模式(二) Java中的动态代理
    Java 代理模式(一) 静态代理
    CGLib动态代理原理及实现
    Understanding sun.misc.Unsafe
    Finding Memory Leaks with SAP Memory Analyzer
    ubuntu18.04 安装mysql server
    Sqoop+mysql+Hive+ Ozzie数据仓库案例
  • 原文地址:https://www.cnblogs.com/mthoutai/p/7100469.html
Copyright © 2020-2023  润新知