劍指offer(三十三)——醜數
題目描述
把只包含質因子2、3和5的數稱作醜數(Ugly Number)。例如6、8都是醜數,但14不是,因爲它包含質因子7。 習慣上我們把1當做是第一個醜數。求按從小到大的順序的第N個醜數。
題解
理解題意很重要,咋一看會感覺醜數很複雜,但實際上你把它列出來就會發現,醜數定義是比較簡單的。1、2、3、4、5、6、8、9、10、12、15、18、20、25……仔細琢磨就會發現
- 2=1*2
- 3=1*3
- 5=1*5
- 4=2*2
- 6=2*3
- 10=2*5
- 6=3*2
- 9=3*3
- 15=3*5
- ……
可以看出來醜數都是由醜數相乘得來的。在知道了定義之後我們能做什麼?這裏有一位大佬的解釋就很清楚。
鏈接:https://www.nowcoder.com/questionTerminal/6aa9e04fc3794f68acf8778237ba065b?f=discussion
來源:牛客網維護三個隊列:
(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
這樣看思路是不是比較明朗了?但是3個隊列就顯得比較麻煩,所以我們用3個指針也可以達到相同的效果。
- p1、p2、p3三個指針用來取代隊列的作用,由於默認1是醜數數組的第一位,所以先讓指針指向醜數數組list[0],分別乘上2、3、5,結果中最小的便是下一位醜數,這裏是2。
- 將2存入list中,並移動指針p1,然後重複乘上2、3、5,結果最小即是下一位醜數。
- 這樣便可以求出題目所要求的數了。
public int GetUglyNumber_Solution(int index) {
if (index < 7) {
return index;
}
ArrayList<Integer> list = new ArrayList<>();
list.add(1);
int i, p1 = 0, p2 = 0, p3 = 0;
for(i = 1; i < index; i++) {
int mulTwo = list.get(p1) * 2;
int mulThr = list.get(p2) * 3;
int mulFiv = list.get(p3) * 5;
int minNum = Math.min(mulTwo, Math.min(mulThr, mulFiv));
list.add(minNum);
if (minNum == mulTwo) {
p1++;
}
if (minNum == mulThr) {
p2++;
}
if (minNum == mulFiv) {
p3++;
}
}
return list.get(index - 1);
}