刷題-醜數提取及醜數判斷

題目描述:

把只包含質因子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;//遞歸調用
    }
};

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章