思路:
由题目中给到的信息:
- 丑数仅由2、3、5的因子组成
- 1是第一个丑数
现在要寻找第n个丑数,最简单值观的方法莫过于从1开始依次往后递增加1,判断每个数是否将2除尽、3除尽、5除仅为1且不含余数,若是则丑数加1,继续往后找。此方法问题在于随着数字不断增大,要除尽2、3 、5需要多次循环,且中间会计算很多非丑数,十分浪费时间,也确实会超时。 因此需要换思路。
方法一:235乘法 由上方列出的条件可知,丑数由1乘上2或3或5,并在这个基础上不断乘2或3或5组成,且因其是递增的,我们便可以从开始,给前面找到丑数乘上2,3,5,且要它们中大于最后一个找到的丑数中的最小值。 比如:第一个丑数1 1 x 2 = 2 1 x 3 = 3 1 x 5 = 5 则第二个丑数为2,继续便是: 1 x 2 = 2,2 x 2 = 4 1 x 3 = 3 1 x 5 = 5 则第三个丑数为3,继续便是: 1 x 2 = 2,2 x 2 = 4 1 x 3 = 3,2 x 3 = 6 1 x 5 = 5 第四个丑数为4 ……………… 代码如下:
class Solution {
public:
int findMin(int x, int y, int z){ //寻找三个数中的最小值
int res = x;
res = y < res ? y : res;
res = z < res ? z : res;
return res;
}
int GetUglyNumber_Solution(int index) {
if(index == 0)
return 0; //第一个丑数为1,第0个没有
vector<int> num;
num.push_back(1);
int count = 1; //记录第几个丑数
int x = 0, y = 0, z = 0;
while(count < index){
for(int i = 0 ; i < count; i++){ //找到与2相乘第一个大于num中末尾的数
if(num[i] * 2 > num[count - 1]){
x = num[i] * 2;
break;
}
}
for(int i = 0 ; i < count; i++){ //找到与3相乘第一个大于num中末尾的数
if(num[i] * 3 > num[count - 1]){
y = num[i] * 3;
break;
}
}
for(int i = 0 ; i < count; i++){ //找到与5相乘第一个大于num中末尾的数
if(num[i] * 5 > num[count - 1]){
z = num[i] * 5;
break;
}
}
num.push_back(findMin(x, y, z));//将找到的最小值加入数组
count++;
}
return num[count - 1];
}
};
复杂度分析:
- 时间复杂度:O(n^2),双层for循环
- 空间复杂度:O(n),vector存储每一个丑数
方法二:235乘法改进——贪心思想 上述方法虽然比暴力判断每一个数是否是丑数要节省不少时间,但是我们依然可以发现,它重复计算了很多前面部分——那部分肯定不会再比最后一个已知丑数大了,因此我们可以采取方法避免:用下标递增来表示,当已经运算过后就让下标永久加1.
class Solution {
public:
int findMin(int x, int y, int z){ //寻找三个数中的最小值
int res = x;
res = y < res ? y : res;
res = z < res ? z : res;
return res;
}
int GetUglyNumber_Solution(int index) {
if(index == 0)
return 0; //第一个丑数为1,第0个没有
vector<int> num;
num.push_back(1);
int count = 1; //记录第几个丑数
int x = 0, y = 0, z = 0; //x,y,z分别代表要乘上2 3 5的下标
while(count < index){
num.push_back(findMin(num[x] * 2, num[y] * 3, num[z] * 5));
count++;
if(num[count - 1] == num[x] * 2)
x++; //由2与已知丑数相乘得到的丑数,那该下标及之前的在2这里都用不上了
if(num[count - 1] == num[y] * 3)
y++; //由3与已知丑数相乘得到的丑数,那该下标及之前的在3这里都用不上了
if(num[count - 1] == num[z] * 5)
z++; //由5与已知丑数相乘得到的丑数,那该下标及之前的在5这里都用不上了
}
return num[count - 1];
}
};
复杂度分析:
- 时间复杂度:O(n),只遍历一次
- 空间复杂度:O(n),存储丑数的vector