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