1. 程式人生 > 其它 >劍指 offer程式碼解析——面試題34醜數

劍指 offer程式碼解析——面試題34醜數

本題詳細解析均在程式碼註釋中:

/**
 * 題目:我們把只包含因子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));
	}
}