把只包含質因子2、3和5的數稱作醜數(Ugly Number)。例如6、8都是醜數,但14不是,因為它包含質因子7。 習慣上我們把1當做是第一個醜數。求按從小到大的順序的第N個醜數。
/* 思路: 通俗易懂的解釋: 首先從醜數的定義我們知道,一個醜數的因子只有2,3,5,那麼醜數p = 2 ^ x * 3 ^ y * 5 ^ z,換句話說一個醜數一定由另一個醜數乘以2或者乘以3或者乘以5得到,那麼我們從1開始乘以2,3,5,就得到2,3,5三個醜數,在從這三個醜數出發乘以2,3,5就得到4,6,10,6,9,15,10,15,25九個醜數,我們發現這種方法會得到重複的醜數,而且我們題目要求第N個醜數,這樣的方法得到的醜數也是無序的。那麼我們可以維護三個佇列: (1)醜數陣列: 1 乘以2的佇列:2 乘以3的佇列:3 乘以5的佇列:5 選擇三個佇列頭最小的數2加入醜數陣列,同時將該最小的數乘以2,3,5放入三個佇列; (2)醜數陣列:1,2 乘以2的佇列:4 乘以3的佇列:3,6 乘以5的佇列:5,10 選擇三個佇列頭最小的數3加入醜數陣列,同時將該最小的數乘以2,3,5放入三個佇列; (3)醜數陣列:1,2,3 乘以2的佇列:4,6 乘以3的佇列:6,9 乘以5的佇列:5,10,15 選擇三個佇列頭裡最小的數4加入醜數陣列,同時將該最小的數乘以2,3,5放入三個佇列; (4)醜數陣列:1,2,3,4 乘以2的佇列:6,8 乘以3的佇列:6,9,12 乘以5的佇列:5,10,15,20 選擇三個佇列頭裡最小的數5加入醜數陣列,同時將該最小的數乘以2,3,5放入三個佇列; (5)醜數陣列:1,2,3,4,5 乘以2的佇列:6,8,10, 乘以3的佇列:6,9,12,15 乘以5的佇列:10,15,20,25 選擇三個佇列頭裡最小的數6加入醜數陣列,但我們發現,有兩個佇列頭都為6,所以我們彈出兩個佇列頭,同時將12,18,30放入三個佇列; …………………… 疑問: 1.為什麼分三個佇列? 醜數數組裡的數一定是有序的,因為我們是從醜數數組裡的數乘以2,3,5選出的最小數,一定比以前未乘以2,3,5大,同時對於三個佇列內部,按先後順序乘以2,3,5分別放入,所以同一個佇列內部也是有序的; 2.為什麼比較三個佇列頭部最小的數放入醜數陣列? 因為三個佇列是有序的,所以取出三個頭中最小的,等同於找到了三個佇列所有數中最小的。 實現思路: 我們沒有必要維護三個佇列,只需要記錄三個指標顯示到達哪一步;“|”表示指標,arr表示醜數陣列; (1)1 |2 |3 |5 目前指標指向0,0,0,佇列頭un_arr[0] * 2 = 2, un_arr[0] * 3 = 3, un_arr[0] * 5 = 5 (2)1 2 2 |4 |3 6 |5 10 目前指標指向1,0,0,佇列頭un_arr[1] * 2 = 4, un_arr[0] * 3 = 3, un_arr[0] * 5 = 5 (3)1 2 3 2| 4 6 3 |6 9 |5 10 15 目前指標指向1,1,0,佇列頭un_arr[1] * 2 = 4, un_arr[1] * 3 = 6, un_arr[0] * 5 = 5 ……………… */
class Solution { public: int GetUglyNumber_Solution(int index) { if(index<7) return index; vector<int> un_arr(index); int t2 = 0,t3 = 0,t5 = 0; un_arr[0] = 1; for(int i=1;i<index;++i){ un_arr[i] = min(un_arr[t2]*2,min(un_arr[t3]*3,un_arr[t5]*5)); if(un_arr[i]==un_arr[t2]*2) t2++; if(un_arr[i]==un_arr[t3]*3) t3++; if(un_arr[i]==un_arr[t5]*5) t5++; } return un_arr[index-1]; } };