剑指offer(35):丑数

题目描述

把只包含因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。

分析

直接思路:遍历从1开始遍历,求出第n个丑数。但是每个整数都需要判断,即使1个数字不是丑数,还是需要对它做求余数和除法操作。

牛客AC:

public int GetUglyNumber_Solution2(int index) {
        if (index <= 0)
            return 0;
        int number = 0;
        int uglyNumCount = 0;
        while (uglyNumCount < index) {
            number++;
            if (isUglyNumber(number)) {
                uglyNumCount++;
            }
        }
        return number;
    }

    private boolean isUglyNumber(int number) {
        while (number % 2 == 0)
            number /= 2;
        while (number % 3 == 0)
            number /= 3;
        while (number % 5 == 0)
            number /= 5;
        return (number == 1) ? true : false;
    }
}

推荐思路

根据丑数的定义,一个丑数可以有另一个丑数乘以2、3或者5(1除外)得到。可以创建一个数组,里面是排序的丑数,每一个丑数都是前面的丑数乘以2、3或者5得到的。

我们开辟一个index长度数组作为储存空间,逐一放入达到目标前的每个丑数,以空间换时间。用t2,t3,t5来标记已储存丑数中分别乘以2,3以及5可以大于目前最大丑数的索引,每次确定下一个最大丑数时,即判断t2,t3,t5索引处哪个数乘以相应倍数得到的结果更小,然后填充新丑数,之后按照确定t2,t3,t5规则更新这些索引即可。

牛客AC:

package com.problem;

public class UglyNum {
    public int GetUglyNumber_Solution(int index) {
        if(index <= 0)
            return 0;

        int[] uglyNums = new int[index];    // 存放丑数
        uglyNums[0] = 1;    // 第1个丑数
        int nextUglyNumIndex = 1; // 下一个丑数索引

        // 对于乘以2而言,肯定存在某一个丑数T2,排在它之前的每一个丑数乘以2得到的结果
        // 都会小于已有最大丑数,在它之后的每一个丑数乘以2都大于已有最大丑数。
        // 乘以3/5也是如此,记录下T2、T3、T5的索引,每次生成时用T2、T3、T5乘以对应的因子
        // 再去3个乘积结果的最小值就是新的最大丑数,同时判断更新对应的下标即可。
        int multiply2Index = 0; 
        int multiply3Index = 0;
        int multiply5Index = 0;

        while(nextUglyNumIndex < index) {
            // 获取最小值为新的丑数
            int minVal = min(uglyNums[multiply2Index] * 2, 
                            uglyNums[multiply3Index] * 3,
                            uglyNums[multiply5Index] * 5);
            uglyNums[nextUglyNumIndex] = minVal;

            // 更新下标
            if(uglyNums[multiply2Index] * 2 == minVal)
                multiply2Index++;
            if(uglyNums[multiply3Index] * 3 == minVal)
                multiply3Index++;
            if(uglyNums[multiply5Index] * 5 == minVal)
                multiply5Index++;

            // 下一个丑数索引加1
            nextUglyNumIndex++;
        }
        return uglyNums[nextUglyNumIndex - 1];
    }

    // 获取3个数字的最小值
    public int min(int num1, int num2, int num3) {
        int minVal = (num1 < num2) ? num1 : num2;
        minVal = (minVal < num3) ? minVal : num3;
        return minVal;
    }
}

参考
1. 何海涛,剑指offer名企面试官精讲典型编程题(纪念版),电子工业出版社

你可能感兴趣的:(丑数,剑指offer)