题目
丑数: 一个数分解质因数后只包括2、3、 5,就说明这是一个丑数。1 是 丑数
丑数就是只包含质因数 2, 3, 5 的正整数。
问题1:
判断一个数是否是丑数
思路
根据手动(就是在纸上手算)分解质因数的思路, 首先尝试2,直至不能再被 2 整除,然后试 3 , 然后 5. 最后如果商为 1 说明是丑数
如果不是 1 那么就说明不是丑数。
代码
#include<iostream>
#include<vector>
using namespace std;
// 判断一个数是不是丑数: 按照手动的分解质因数的方法,从 2 试起,知道不能再分,然后 3 .. 5
class Solution {
public:
bool isUgly(int num)
{
if (num == 0)
return false;
if (num == 1)
return true;
int n = num;
if ((num % 2 == 0) || (num % 3 == 0) || (num % 5 == 0))
{
while(n % 2 == 0 && n != 0)
{
n = n / 2;
}
while (n % 3 == 0 && n != 0)
{
n = n / 3;
}
while (n % 5 == 0 && n != 0)
{
n = n / 5;
}
if (n == 1)
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
};
问题2
计算第 n 个丑数
思路
通过遍历每个数,判断是否是丑数会超时。
丑数都是 2 3 5 乘积得到的,所以可以采用生成丑数的方式, 问题要求第 n 个,所以生成的丑数需要保证有序,并且不能漏掉任何一个丑数。
三指针法: 使用三个标志位,分别标记已经计算出的丑数乘以2、3、5刚好大于已经计算出的最后一个丑数(即当前最大值)的数组索引。
然后取三个乘积中的最小值,就是下一个丑数,并保存。更新三个标志。直至得到的丑数数量为 n 返回第 n 个值
代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
// 计算第 n 个丑数
class Solution {
public:
// 思路:通过生成丑数的方法,三种生成方式最小的就是下一个丑数
// 生成方式:已经得到的丑数分别乘以 2 3 5
// 2 3 5 三种方式的因数通过数组下标记录,每生成一个丑数,更新三种方式的下标,更新为乘积刚好大于最新的丑数的值
int min(int a, int b, int c)
{
int x = a < b ? a : b;
return x < c ? x : c;
}
int nthUglyNumber(int n)
{
if (n == 0)
return 0;
int cur = 1; // 当前最大丑数
int number = 0; // 已经计算出的丑数数量
int index_2 = 0;
int index_3 = 0;
int index_5 = 0;
vector<int> numbers(n, 0);
numbers[0] = 1;
while (number < n-1)
{
cur = min(numbers[index_2] * 2, numbers[index_3] * 3, numbers[index_5] * 5);
number++;
numbers[number] = cur;
// 寻找与 2 3 5 相乘的起始值
while (numbers[index_2] * 2 <= cur)
{
index_2++;
}
while (numbers[index_3] * 3 <= cur)
{
index_3++;
}
while (numbers[index_5] * 5 <= cur)
{
index_5++;
}
}
return numbers[number];
}
};