刷题-丑数提取及丑数判断

题目描述:

把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。

问题分析:

根据丑数的定义,我们知道丑数一定是由2、3、5乘积得到,可表示成如下公式:

                                                                             x=2^{^{i}}\times 3^{^{j}}\times 5^{^{k}}

我们默认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:

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:24、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;
    }
};

引申:判断一个数是否为丑数:

判断一个数是否为丑数的思路:就是这个数是否可以分解为:x=2^{^{i}}\times 3^{^{j}}\times 5^{^{k}},解题思路:

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;//递归调用
    }
};

猜你喜欢

转载自blog.csdn.net/iea5357/article/details/106982617