《剑指offer》面试题49:丑数

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


设计一个算法,找出只含素因子2,3,5 的第 n 小的数。符合条件的数如:1, 2, 3, 4, 5, 6, 8, 9, 10, 12…

思路:

思路1:从1开始递增,依次判断每个数是否是丑数,不够高效;
思路2:思路1之所以效率低,比较关键的一点是遍历的每一个数字都进行丑数判断。思路2不是去判断丑数,而是计算出丑数:因为每个丑数都可以看成是由1去乘以2、3、5,再乘以2、3、5而衍生出来的。可以用三个指针指向第一个丑数1,三个指针分别表示乘2,乘3,乘5,将三个指针计算出来的最小的丑数放在数组中,并将该指针向后移动一个位置。为了得到第1500个丑数,需要一个长度1500的数组来记录已经计算出来的丑数。因此这个思路也可以说是用空间换时间。

基于以上思路,java参考代码如下:

public class GetUglyNumber_Solution {
//思路一:判断每个数是否是丑数
	public static int getUglyNumber(int num){
        if(num<=0)
            return 0;
        int number = 0,uglyFound = 0;
        while (uglyFound<num){
            number++;
            if(isUgly(number))
                uglyFound++;
        }
        return number;
   }
   public static boolean isUgly(int number){
       while (number%2==0)
           number/=2;
       while (number%3==0)
           number/=3;
       while (number%5==0)
           number/=5;
       return number==1;
   }

//思路二:用空间换时间
    public static int getUglyNumber2(int n) {
        if(n<=0)
            return 0;
        if(n==1)
            return 1;
        int[] nums = new int[n];
        nums[0] = 1;
        //用三个指针指向第一个丑数1,三个指针分别表示乘2,乘3,乘5,
        //将三个指针计算出来的最小的丑数放在数组中,并将该指针向后移动一个位置
        int p2 = 0,p3 = 0,p5 = 0;
        for(int i=1;i<n;i++){
            nums[i] = Math.min(nums[p2]*2,Math.min(nums[p3]*3,nums[p5]*5));
            // //2*3=6,3*2=6,会有重复值,因此下面需要使用if,而不能用if-else
            if(nums[i]==nums[p2]*2) p2++;
            if(nums[i]==nums[p3]*3) p3++;
            if(nums[i]==nums[p5]*5) p5++;
        }
        return nums[n-1];
    }

	public static void main(String[] args) {
        System.out.println(getUglyNumber(10));
        System.out.println(getUglyNumber2(10));
	}

}
测试用例:

a.功能测试(输入2,3,4,5,6等)。
b.特殊输入测试(边界值1;无效输入0)。
c.性能测试(输入较大的数字,如1500)。

参考:

https://www.jianshu.com/p/75bd206d865d
https://www.cnblogs.com/hglibin/p/9030315.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值