劍指Offer 第34題 醜數 java

2021-09-11 20:48:39 字數 1701 閱讀 2681

題目:醜數

* 我們把只包含因子2,3,5的數稱為醜數(ugly number).

* 求按從小到大的順序的第1500個醜數。

* 例如6,8都是醜數,但14不是,因為它含有因子7.習慣上我們把1當作第乙個醜數

方法一:逐個判斷每個整數是不是醜數的解法,直觀但不夠高效:

所謂乙個數m是另乙個數n的因子,是指n能被m整除,也就是說n%m==0.根據醜數的定義,醜數只能被2,3,5整除。也就是說如果乙個數能被2整除,我們把它連續除以2;如果能被3整除,就連續除以3;如果能被5整除,就除以5.如果最後我們得到的是1,那麼這個數就是醜數,否則不是。

接下來,我們只需要按照順序判斷每個整數是不是醜數,

我們只需要在函式getuglynumber 中傳入引數1500,就能得到第1500個醜數。該演算法非常直觀,**也非常簡介,但最大的問題是每個整數都需要計算。即使乙個數字不是醜數,我們還是需要對它做求餘和除法操作。因此該演算法的時間效率不是很高,面試官也不會就此滿足,還會提示我們有更高效的演算法。

方法二:建立陣列儲存已經找到的醜數,用空間換時間的解法:

前面的演算法之所以效率低,很大程度上是因為不管乙個數是不是醜數我們對它都要作計算。接下來我們試著找到一種只要計算醜數的方法,而不在非醜數的整數上花費時間。根據醜數的定義,醜數應該是另乙個醜數乘以2,3,5的結果。因此我們可以建立乙個陣列,裡面的數字是排序好的醜數,每乙個醜數都是前面的醜數乘以2,3,5得到的。

這種思路的關鍵在於怎樣確定陣列裡面的醜數是排序好的。假設陣列中已經有若干個醜數排好後存放在陣列中,並且把已有的最大的醜數記作m,我們接下來分析如何生成下乙個醜數。該醜數肯定是前面某個醜數乘以2,3,5的結果。所以我們首先考慮把已有的每個醜數乘以2.在乘以2的時候,能得到若干個小於或等於m的結果。由於是按照順序生成的,小於或者等於m肯定已經在陣列中了,我們不需要再次考慮;還會得到若干個大於m的結果,但我們只需要第乙個大於m的結果,因為我們希望醜數是指按從小到大的順序生成的,其他更大的結果以後再說。我們把得到的第乙個乘以2後大於m的結果即為m2.同樣,我們把已有的每乙個醜數乘以3,5,能得到第乙個大於m的結果m3和m5.那麼下乙個醜數應該是m2,m3,m5。這3個數的最小者。

前面分析的時候,提到把已有的每個醜數分別都乘以2,3,5.事實上這不是必須的,因為已有的醜數都是按順序存放在陣列中的。對乘以2而言,肯定存在某乙個醜數t2,排在它之前的每乙個醜數乘以2得到的結果都會小於已有的最大醜數,在它之後的每乙個醜數乘以2得到的結果都會太大。我們只需記下這個醜數的位置,同時每次生成新的醜數的時候,去更新這個t2.對乘以3和5而言,也存在這同樣的t3和t5.

**:

public class offer34 

public int getuglynumber(int index){

if(index <= 0)

return 0;

int number = 0;

int uglyfound = 0;

while(uglyfound 執行結果:

第2個醜數是: 2

第3個醜數是: 3

第4個醜數是: 4

第5個醜數是: 5

第6個醜數是: 6

第1個醜數是: 1

第0個醜數是: 0

第1500個醜數是: 859963392

劍指offer 34 醜數

只包含因子2 3 5的數稱為醜數。方法1 逐個判斷每個整數是不是醜數 方法2 建立陣列儲存已經找到的醜數,用空間換時間的方法 每乙個醜數都是前面的醜數乘以2 3 5得到的 已有醜數中最大醜數為m,下乙個醜數應該是已知醜數分別乘以2 3 5的第乙個大於m的數,記錄,每個乘以2 3 5第乙個大於m的位置...

劍指Offer 34 醜數

把只包含因子2 3和5的數稱為醜數,求從小到大的順序的第1500個數。1是第乙個醜數。乙個醜數可以表示成2m3 n5 k2 m3 n5 k 2m3n5k 其中,m n k為自然數zzz。醜數從小到大的順序其實是m n k這三個數中的其中乙個數加一。生成過程 陣列res初始化,儲存了第乙個元素res ...

劍指offer 34 醜數

把只包含質因子2 3和5的數稱作醜數 ugly number 例如6 8都是醜數,但14不是,因為它包含質因子7。習慣上我們把1當做是第乙個醜數。求按從小到大的順序的第n個醜數。看到這個問題的時候可以這樣想 解題思路 因為乙個醜數隻包含質因子2 3和5,也就是說乙個醜數一定由另乙個醜數乘以2或者乘以...