1. 程式人生 > 實用技巧 >面試題49:醜數

面試題49:醜數

把只包含質因子2、3和5的數稱作醜數(Ugly Number)。例如6、8都是醜數,但14不是,因為它包含質因子7。 習慣上我們把1當做是第一個醜數。求按從小到大的順序的第N個醜數。

解題思路

  • 暴力列舉法(會超時,一般的C++程式執行10^9次就會超過1s而超時
  • 空間換時間,儲存已計算的醜數,並通過已計算的醜數預測未來的醜數

上程式碼(C++香)

法一:暴力列舉法(超時)
#define maxN 10010
#define maxNN 0xFFFFFFF

// 判斷是否是素數
bool isPrime(int num){
    // 1不是素數
    if(num < 2)
        return false;
    // 2是素數,不會執行for
    for(int i = 2; i < num; i++){
        if(!(num % i))
            return false;
    }
    return true;
}

// 先求出一部分素數,陣列下標為素數標記
void primeCache(int num[]){
    for(int i = 0; i <= maxN; i++){
        if(isPrime(i))
            num[i] = 1;
    }
}

// 先求出一部分素數,陣列值為素數標記
void primeCachePlus(int num[]){
    int m = 0;
    for(int i = 2; i <= maxN; i++){
        if(isPrime(i))
            num[m++] = i;
    }
}

bool isUglyNum(int prime[], int num){

    if(num <= 1)
        return true;

    if(num % 2 != 0 && num % 3 != 0 && num % 5 != 0)
        return false;

    for(int i = 3; prime[i] <= num; i++){
        // 不為0
        if(!(num % prime[i]))
            return false;
    }
    return true;
}

int GetUglyNumber_Solution(int index) {

    // 得到素數快取
    int num[maxN];
    memset(num, -1, sizeof(num));
    primeCachePlus(num);

    // 找到所有的醜數
    int m = 0;
    for(int i = 1; i <= maxNN; i++){
        if(isUglyNum(num, i)){
            m++;
            if(m == index)
                return i;
        }
    }
}
法二:暴力列舉法(超時,但這樣的做法更妙)
bool isUgly(int number){
    while(number % 2 == 0)
        number /= 2;
    while(number % 3 == 0)
        number /= 3;
    while(number % 5 == 0)
        number /= 5;
    return (number == 1) ? true : false;
}

// 這樣也會超時
int GetUglyNumber_SolutionPlus(int index) {

    int number = 0;
    int uglyFound = 0;
    while(uglyFound < index){
        number++;
        if(isUgly(number))
            uglyFound++;
    }
    return number;
}
法三:空間換時間,儲存已計算的醜數,並通過已計算的醜數預測未來的醜數(AC)
int myMin(int number1, int number2,int number3){
    int min = (number1 < number2) ? number1 : number2;
    return (min < number3) ? min : number3;
}

int GetUglyNumber_Solution(int index) {

    if(index <= 0)
        return 0;

    int pUglyNumbers[index];
    memset(pUglyNumbers, -1, sizeof(pUglyNumbers));
    pUglyNumbers[0]= 1;
    int nextUglyIndex = 1;

    int* pMultiply2 = pUglyNumbers;
    int* pMultiply3 = pUglyNumbers;
    int* pMultiply5 = pUglyNumbers;

    while(nextUglyIndex < index){
        // 求出當前最大的醜數
        pUglyNumbers[nextUglyIndex] = myMin(*pMultiply2 * 2, *pMultiply3 * 3, * pMultiply5 * 5);
        // 更新M2
        while(*pMultiply2 * 2 <= pUglyNumbers[nextUglyIndex])
            pMultiply2++;
        while(*pMultiply3 * 3 <= pUglyNumbers[nextUglyIndex])
            pMultiply3++;
        while(*pMultiply5 * 5 <= pUglyNumbers[nextUglyIndex])
            pMultiply5++;

        nextUglyIndex++;
    }
    return pUglyNumbers[index - 1];

}