有关leetcode中丑数Ugly Number

1.定义:什么是丑数?

一般的丑数 是 指其 素数因子 只含 2, 3 ,5

所以,第一题:如何判断一个正数n是否为丑数;

由于丑数中只含素数因子 2,3,5,所以一个数如果是丑数,则必然是 2,3,5的相互相乘的组合,所以我们可以让 n先除以2,直至不能除为止,然后除以3,直至不能除为止,最后除以5,直至不能除(即有余数)为止,判断:如果最后的商为1,则说明该数是丑数

所以,代码如下:

class Solution {
public:
    bool isUgly(int num) 
    {
        if(num <= 0)
        {
            return false;
        }
        int tmpnum = num;
        for(int i = 2; i < 6; i++)
        {
            if(i == 4)//其实该行代码是多余的,去掉后并不影响,因为4相当于2*2
            {
                continue;
            }
            while(tmpnum%i == 0)
            {
                tmpnum /= i;
            }
        }

        return tmpnum == 1;
        
        
    }
};

2.现在我们升级,我们不仅要求是丑数,而且要只知道 从小到大 的第n个丑数是多少;

那么如何求 第n个丑数呢?由于是丑数,所以必须是 规定素数的组合,(规定1也是丑数)

我们已经知道 1 是丑数,则第二个丑数必然是 1*2 1*3 1*5中最小的一个即2;

现在丑数列变为 1 ,2;

所以第三个丑数变为2*2,1*3,1*5中最小的一个即3,

现在丑数列变为1,2,3;

所以第四个丑数变为2*2,2*3,1*5中最小的一个即4,

现在丑数列变为1,2,3,4.

所以第五个丑数变为3*2,2*3,1*5中最小的一个,即5

现在丑数列变为1,2,3,4,5

所以第六个处理变为3*2,2*3,2*5中最小的一个(有两个 6)

所以现在丑数列变为1,2,3,4,5,6但是要注意,第七个丑数就不能再是6了,所以上面的 3*2  与 2*3均需要+1

变为 4*2 与 3*3;之后同理

所以总结下来就是 将 丑数列中的指针指向的乘子(每一个素数对应一个移动指针,指向丑数列中的乘子)均与 素数 2,3,5相乘,选出最小的一个乘积作为 下一个丑数,然后用到指针需要向右移到一位 

代码:

class Solution {
public:
    int nthUglyNumber(int n) 
    {
        vector<int> vec(n+1,0);
        vec[1] = 1;
        int p2 = 1, p3 = 1, p5 = 1;
        //p2,p3,p5分别为对应 素数因子2,3,5的指针
        for(int i = 2; i <= n; i++)
        {
            vec[i] = min(vec[p2]*2,min(vec[p3]*3,vec[p5]*5));
            if(vec[i] == vec[p2]*2) p2++;
            if(vec[i] == vec[p3]*3) p3++;
            if(vec[i] == vec[p5]*5) p5++;
        }
        return vec[n];
        
    }
};

接下来,进一步的,定义超级丑数,是一系列 素数因子的乘积;问第n个 超级丑数是多少?

其实该题与上一题基本是类似的,只不过是 素数因子变多了而已,

但是核心思想不变, 有几个素数因子,我们就定义几个指向丑数列的 指针,指针起始都指向同一个位置,然后与素数因子相乘后选出的最小丑数后要将该指针进行右移;

由于 该题中 primes素数因子是一个数组,所以我们将 指向丑数列的指针也定义为一个数组,与 primes大小相同,因为他们要一一对应,然后设丑数列 为  res(n,0); res[0] = 1;

所以 第二个丑数为 res[1] = min(res[index[i])*primes[i]);

并且需要判断哪些指针需要右移

class Solution {
public:
    int nthSuperUglyNumber(int n, vector<int>& primes) 
    {
        
        vector<int> res(n,0);
        res[0] = 1;
        int len = primes.size();
        vector<int> index(len,0);//定义指针,与primes个数匹配
        for(int i = 1; i < n; i++)
        {
            res[i] = helper(res,index,primes);
            for(int j = 0; j < len; j++)
            {
                if(res[i] == res[index[j]]*primes[j])
                {
                    index[j]++;
                }
            }
        }
        return res[n-1];
        
        
    }
    
private:
    int helper(vector<int>& res, vector<int>& index,vector<int>& primes)
    {
        int Min = INT_MAX;
        for(int i = 0; i < primes.size(); i++)
        {
            Min = min(Min,res[index[i]]*primes[i]);
        }
        return Min;
    }
    
    
    
};

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值