面試題34:醜數
1.題目描述
我們把只包含因子2、3和5的數稱作醜數。求按從小到大的順序的第1500個醜數。例如6(6=3*2)、8(8=2*4,4=2*2)都是醜數,但14不是,因爲它包含因子7。習慣上我們把1當做第一個醜數。
2.題目分析
根據醜數的定義,醜數應該是另一個醜數乘以2、3或者5的結果(1除外)。因此我們可以創建一個數組,裏面的數字是排好序的醜數,每一個醜數都是前面的醜數乘以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。
3.code
int Min(int number1, int number2, int number3)
{
int min = (number1 < number2) ? number1 : number2;
min = (min < number3) ? min : number3;
return min;
}
int GetUglyNumber_Solution2(int index)
{
if (index <= 0) return 0;
int* pUglyNumbers = new int[index];
pUglyNumbers[0] = 1;
int nextUglyIndex = 1;
int* pMultiply2 = pUglyNumbers;
int* pMultiply3 = pUglyNumbers;
int* pMultiply5 = pUglyNumbers;
while (nextUglyIndex < index)
{
int min = Min(*pMultiply2 * 2, *pMultiply3 * 3, *pMultiply5 * 5);
pUglyNumbers[nextUglyIndex] = min;
while (*pMultiply2 * 2 <= pUglyNumbers[nextUglyIndex]) ++pMultiply2;
while (*pMultiply3 * 3 <= pUglyNumbers[nextUglyIndex]) ++pMultiply3;
while (*pMultiply5 * 5 <= pUglyNumbers[nextUglyIndex]) ++pMultiply5;
++nextUglyIndex;
}
int ugly = pUglyNumbers[nextUglyIndex - 1];
delete[] pUglyNumbers;
return ugly;
}