面試題34:醜數面試題9:斐波那契數列

來源:互聯網
上載者:User
題目:我們把只包含因子2,3和5的數稱作為醜數。求按從小到大的順序的第1500個醜數。例如6,8都是醜數,但是14不是,因為它包含因子7。習慣上我們把1作為第一個醜數。
方法一:遍曆法

使用遍曆法求第k個醜數,從1開始遍曆,如果是醜數則count++,直到count==k為止。那麼如何判斷醜數呢?根據醜數的定義,醜數只有2,3,5這三個因子,那麼我們就拿數字除以這三個因子。具體演算法如下:

  1. 如果一個數能夠被2整除,那麼讓他繼續除以2;
  2. 如果一個數能夠被3整除,那麼讓他繼續除以3;
  3. 如果一個數能夠被5整除,那麼讓他繼續除以5;
  4. 如果最後這個數變為1,那麼這個數就是醜數,否則不是。

代碼實現如下:

View Code

#include<iostream>#include<stdlib.h>#include<cassert>#include<time.h>using namespace std;//判斷是否為醜數bool isUgly(int number){    while(number%2==0)        number=number/2;    while(number%3==0)        number=number/3;    while(number%5==0)        number=number/5;    return (number==1)?true:false;}//擷取第k個醜數,假定1為第一個醜數int getUglyNumber(int index){    int number=0;    int count=0;    while(count<index)    {        ++number;        if(isUgly(number))            count++;    }    return number;}int main(){    int k=1500;    clock_t start, end;//用於統計程式已耗用時間    start = clock();    cout<<getUglyNumber(k)<<endl;    end = clock();    cout<<"Run time: "<<(double)(end - start) / CLOCKS_PER_SEC<<"S"<<endl;//要記錄分鐘的話,上面的程式改為(double)(end - start) / CLOCKS_PER_SEC/60即可;    system("pause");    return 0;}

其運行結果如下:

我們發現一共耗時33秒,效能比較低。

方法二:建立醜數數組,用空間還時間

如前所述,我們發現採用遍曆法求第K個醜數的效率十分低下,我們在前面求第1500個醜數花去了33秒的時間,這還是在我I7 3770K的電腦上啟動並執行。所以我們考慮有沒有一種更加高效的方法。在面試題9:斐波那契數列中我們使用了一種“用空間還時間”的方法來提高求斐波那契數列的速度。這種編程思想也可以應用在這道題目當中,我們為所有求出的醜數建立數組,不在非醜數上面浪費時間。

根據醜數的定義,我們可以知道醜數可以由另外一個醜數乘以2,3或者5得到。因此我們建立一個數組,裡面的數字是排好序的醜數,每一個醜數都是前面的醜數乘以2,3或者5得到的。這種思路的關鍵在於怎樣確保數組裡面的數字是排序的。

假設醜數數組中已經有若干個排好序的醜數,比如1,2,3,4,5。我們把當前醜數數組中的最大數記為M,這裡M=5。我們接下來分析如何產生下一個醜數。根據前面的介紹,我們知道這個醜數肯定是前面醜數數組中的數字乘以2,3,5得到的。所以我們首先考慮把已有的每個醜數乘以2,在乘以2的時候,能夠得到若干個小於或者等於M的結果。由於是按照順序產生的,小於或者等於M的數肯定已經在醜數數組當中了,我們不需要再次考慮;當然還會得到若干大於M的結果,但是我們只需要第一個大於M的結果,因為我們希望醜數是按順序排列的,所以其他更大的結果可以以後考慮。我們把得到的第一個乘以2以後得到的大於M的結果記為M2。同樣,我們把已有的每一個醜數乘以3和5,能得到第一個大於M的結果M3和M5。那麼M後面的那一個醜數應該是M2,M3和M5當中的最小值:Min(M2,M3,M5)。比如將醜數數組中的數字按從小到大乘以2,直到得到第一個大於M的數為止,那麼應該是2*2=4<M,3*2=6>M,所以M2=6。同理,M3=6,M5=10。所以下一個醜數應該是6。

前面分析的時候,提到把已有的每個醜數分別都乘以2,3和5。事實上這不是必須的,因為已有的醜數是按順序存放在數組中的,對乘以2而言,肯定存在某一個醜數T2,排在她之前的每一個醜數乘以2得到的結果都會小於等於(<=)已有最大的醜數,在它之後的每一個醜數乘以2得到的結果都會大於已有的最大丑數。因此我們只需要記下這個醜數的位置,同時每次產生新的醜數的時候去更新這個T2。對於乘以3和5,同樣存在這樣的T3和T5。

程式碼範例

View Code

#include<iostream>#include<stdlib.h>#include<cassert>#include<time.h>using namespace std;//求M2,M3,M5的最小值int Min(int number1,int number2,int number3){    int min=(number1<number2)?number1:number2;    return (min<number3)?min:number3;}//擷取第k個醜數,假定1為第一個醜數int getUglyNumber2(int index){    //如果index<=0表明輸入有誤,直接返回0    if(index<=0)        return 0;    //定義醜數數組,用於記錄排序的醜數    int *pUglyNumbers=new int[index];    //第一個醜數為1    pUglyNumbers[0]=1;    //第一個醜數的座標是0,下一個醜數的座標從1開始    int nextUglyIndex=1;    //定義三個指向醜數數組的指標,用它們來標識從數組中的哪一個數開始計算M2,M3和M5,開始都是醜數數組的首地址。    int *T2=pUglyNumbers;    int *T3=pUglyNumbers;    int *T5=pUglyNumbers;    while(nextUglyIndex<index)//    {        int min=Min(*T2 * 2,*T3 * 3,*T5 * 5);//M2=*T2 * 2, M3=*T3 * 3, M5=*T5 * 5        pUglyNumbers[nextUglyIndex]=min;//求M2,M3,M5的最小值作為新的醜數放入醜數數組        //每次產生新的醜數的時候,去更新T2,T3和T5.        while(*T2 * 2<=pUglyNumbers[nextUglyIndex])            ++T2;        while(*T3 * 3<=pUglyNumbers[nextUglyIndex])            ++T3;        while(*T5 * 5<=pUglyNumbers[nextUglyIndex])            ++T5;        nextUglyIndex++;    }    int ugly=pUglyNumbers[index-1];//因為醜數有序排列,所以醜數數組中的最後一個醜數就是我們所求的第index個醜數。    delete[] pUglyNumbers;    return ugly;}int main(){    int k=1500;    clock_t start, end;//用於統計程式已耗用時間    start = clock();    cout<<getUglyNumber2(k)<<endl;    end = clock();    cout<<"Run time: "<<(double)(end - start) / CLOCKS_PER_SEC<<"S"<<endl;//要記錄分鐘的話,上面的程式改為(double)(end - start) / CLOCKS_PER_SEC/60即可;    system("pause");    return 0;}

注意點:在程式最後有delete[] pUglyNumbers;這是因為動態數組與陣列變數不同,動態分配的數組將一直存在,直到程式顯式釋放它為止。普通的陣列變數,只要出了數組的作用於,其記憶體會自動釋放。c++提供delete []運算式釋放指標所指向的數組空間

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.