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;
}
};