劍指 offer程式碼解析——面試題34醜數
阿新 • • 發佈:2022-05-03
本題詳細解析均在程式碼註釋中:
/** * 題目:我們把只包含因子2、3、5的數稱為醜數。求從小到大順序第1500個醜數。習慣上把1稱為第一個醜數。 * @author 大閒人柴毛毛 * @date 2016年3月24日 */ public class UglyNumber { /** * 分析:所謂“只包含因子2、3、5”其實就是隻能由2、3、5相乘得到的數稱為醜數。 * 根據上述特性,醜數的生產過程如下: * 從1開始,分別乘以2、乘以3、乘以5,得到三個新的醜數2、3、5; * 然後再把這三個新的醜數再分別乘以2、乘以3、乘以5,得到9個醜數4、6、10、6、9、15、10、15、25; * 迴圈上述操作,就能源源不斷地生產醜數。 * 但我們發現,以上生產過程無法保證醜數按照從小到大的順序生產,而且生產的醜數中有重複醜數。 * 我們只有確保生產的醜數是有序的,才能得到第1500個醜數。因此,在生產的同時,我們需要確保當前生產的醜數都是有序的。 * 過程如下: * 假設我們已經生產了n個醜數:1……N,接下來我們要生產第n+1個醜數; * 我們需要從前向後將每個醜數分別乘以2,當找到一個剛剛大於N的醜數時停下; * 然後再從1開始,從前向後將每個醜數乘以3,尋找剛剛大於N的醜數; * 同樣的方法將每個醜數乘以5,尋找剛剛大於N的醜數。 * 然後選出三個數中最小值,作為第N+1個醜數。 * 以此類推,直到計算出1500個醜數為止。 * 程式碼如下: */ /** * 計算第n個醜數 * @param n * @return 返回第n個醜數(返回-1表示程式出錯) */ public static int uglyNumber(int n){ //若n小於0 if(n<=0){ System.out.println("n小於1!"); return -1; } //建立一個長度為n的陣列 int[] a = new int[n]; a[0] = 1; //當前醜數個數 int count = 1; //迴圈計算第n個醜數 while(count<n){ int i=0,j=0,z=0; //從頭開始分別乘以2,找到剛剛大於當前最後一個醜數時停下 for(i=0;i<a.length && a[i]*2<=a[count-1];i++); //從頭開始分別乘以3,找到剛剛大於當前最後一個醜數時停下 for(j=0;j<a.length && a[j]*3<=a[count-1];j++); //從頭開始分別乘以5,找到剛剛大於當前最後一個醜數時停下 for(z=0;z<a.length && a[z]*5<=a[count-1];z++); //找出i、j、z的最小值 int min = a[i]*2; if(a[j]*3<min) min = a[j]*3; if(a[z]*5<min) min = a[z]*5; //將最小值作為第n+1個醜數 a[count++] = min; } return a[count-1]; } /** * 測試 */ public static void main(String[] args){ System.out.println(uglyNumber(5)); } }