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

一:题目描述

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

二:解题思路

题目的关键就是对丑数定义的理解

所谓一个数m是另一个数n的因子,是指n能被m整除,n%m==0.

根据丑数的定义,丑数只能被2,3,5整除。

一个数能被2整除,我们就把他连续除以2

如果能被3整除,就连续除以3

如果能被5整除,就连续除以5

如果最后我们得到的是1,那么这个数就是丑数,否则不是

接下来,我们只需要按照顺序判断每一个正数是不是一个丑数就可以了

class Solution {
public:
    
    bool IsUgly(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;
    }
    
    int GetUglyNumber_Solution(int index) {
    	
        if(index<=0)
            return 0;
        int number=1;
        int numOfUgly=1;
        while(numOfUgly<index){
            number++;
            if(IsUgly(number))
                numOfUgly++;
                
        }
        return number;
    }
};

在牛客网上会超时

前面的算法之所以效率低,很大程度上是对非丑数也进行了操作

接下来我们介绍一种只要计算丑数的方法

根据丑数的定义,丑数应该是另一个丑数乘以2,3,5的结果(1除外)

因此我们只需要创建一个数组,里面的数字是排序好的丑数,每一个丑数都是前面丑数乘以2,3,5得到

这个思路的关键是在于怎么确保数组中丑数都是排序好的?

假设数组中已经存放若干个排好序的丑数,并且把最大的丑数记为M。,接下来如何生成下一个丑数?

该丑数一定是前面的丑数乘以2,3,5的结果。所以

我们考虑把已有的每一个丑数乘以2,再乘以2后,会得到若干个小于等于M的结果,由于是按照顺序生成的,小于等于M的肯定已经在数组中,我们不再考虑;还有若干个大于M的结果,但是我们至于要知道第一个大于M的结果,记作M2.

同理我们可以得到M3,M5.

那么下一个丑数就是M2,M3,M5当中最小的结果。


前面的分析,把已有的每一个丑数乘以2,3,5,是没有必要的。

因为已有的丑数是按照顺序存放在数组中的,对乘以2而言,肯定存在某个丑数T2,排在它前面的每一个丑数乘以2 的结果都会小于等于当前最大的丑数,所以我们只需要记录这个丑数的位置,同时每次生成新的丑数的时候,去更新T2。

同理更新T3,T5

三:代码实现

class Solution {
public:

    
    int Min(int number1,int number2,int number3){
        int min=(number1<number2)?number1:number2;
        min=(min<number3)?min:number3;
        
        return min;
    }
    int GetUglyNumber_Solution(int index) {
          if(index<=0)
              return 0;
          
          int *pUglyNumber= new int[index];
          pUglyNumber[0]=1;//第一个丑数是1
          int nextUglyNumber=1;//代表下一个丑数在数组中的下标
          
          //创建乘子2,3,5三个指针,初始化均指向丑数数组头,用来保存T2,T3,T5
          int *pMultiply2=pUglyNumber;
          int *pMultiply3=pUglyNumber;
          int *pMultiply5=pUglyNumber;
          
          while(nextUglyNumber<index){
              int min=Min(*pMultiply2*2,*pMultiply3*3,*pMultiply5*5);
              pUglyNumber[nextUglyNumber]=min;
              
              //更新T2,T3,T5
              while(*pMultiply2*2<=min)
                  pMultiply2++;
              while(*pMultiply3*3<=min)
                  pMultiply3++;
              while(*pMultiply5*5<=min)
                  pMultiply5++;
              
              nextUglyNumber++;
          }
          int ugly=pUglyNumber[index-1];
          delete[] pUglyNumber;
          return ugly;
      }
};

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值