题目描述:
把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
问题分析:
根据丑数的定义,我们知道丑数一定是由2、3、5乘积得到,可表示成如下公式:
我们默认1是第一个丑数,初始丑数序列为1,从1开始,得到遍历所有丑数的方法:
(1)取丑数序列第1个数1×2、3、5得到2、3、5,丑数序列为1、2、3、5;
(2)取丑数序列第2个数2×2、3、5得到4、6、10,丑数序列为1、2、3、5、4、6、10;
(3)取丑数序列第3个数3×2、3、5得到6、9、15,丑数序列为1、2、3、5、4、6、10、6、9、15;
.......
依次类推,我们是可以遍历得到所有的丑数,但是会发现丑数序列中不断的会出现重复的数,且丑数序列也没有排序,边遍历边排序的方法肯定不是解决问题的方法,期望在此寻找丑数方法的基础上改进。
解题思路:
解题基本思路是分别对基数2、3、5维护3个队列,每个队列记录自己得到的丑数序列:
(1)取丑数序列第1个数1,取3个队列中队头最小的入队,得到丑数序列为1、2
queue_2:2
queue_3:3
queue_5:5
(2)取丑数序列第2个数2,取3个队列中队头最小的入队,得到丑数序列为1、2、3
queue_2:2、4
queue_3:3、6
queue_5:5、10
(3)取丑数序列第2个数3,取3个队列中队头最小的入队,得到丑数序列为1、2、3、4
queue_2:2、4、6
queue_3:3、6、9
queue_5:5、10、15
......依次类推,可以得到一个不含重复元素且排列有序的丑数序列。
程序设计:
解题思路中,通过维护3个序列,实现丑数数列的搜索,设丑数数组为:ugly[ ],通过解题思路中三个队列的数据我们发现,第1列的值为ugly[0]×2、3、5,第2列为ugly[1]×2、3、5,所以可以通过三个标志位flag1、flag2、flag3,分别记录循环处理每步中用于比较的3个值:2×ugly[flag1]、3×ugly[flag2]、5×ugly[flag3],值最小的进入丑数序列,同时标志位+1。
class Solution {
public:
int GetUglyNumber_Solution(int index) {
if(index<7)
return index;
vector<int> ugly;//初始化丑数序列
int flag_1 = 0,flag_2 = 0,flag_3 = 0;//3个标志位
int num = 1;
ugly.push_back(num);
while(ugly.size()<index){
//选出三个队列头最小的数
num = min(2*ugly[flag_1],min(3*ugly[flag_2],5*ugly[flag_3]));
//这三个if有可能进入一个或者多个,进入多个是三个队列头最小的数有多个的情况
if(2*ugly[flag_1] == num) flag_1++;
if(3*ugly[flag_2] == num) flag_2++;
if(5*ugly[flag_3] == num) flag_3++;
ugly.push_back(num);
}
return num;
}
};
引申:判断一个数是否为丑数:
判断一个数是否为丑数的思路:就是这个数是否可以分解为:,解题思路:
class Solution {
public:
bool isUgly(int num){
if(num<1)
return false;
return search(num); //开始递归
}
bool search(int num){
if(num==1)
return true //递归终止
//不是2,3,5的倍数,不是丑数。
if(num%2 != 0 && num%3 != 0 && num%5 != 0 )
return false;
else
return num%2 == 0 ? search(num/2) : false || num%3 == 0 ? search(num/3) : false || num%5 == 0 ? search(num/5) : false;//递归调用
}
};