尋找醜數及關於程式優化效率的一點說明

2021-06-14 22:22:17 字數 3243 閱讀 1989

如果乙個整數值含有因數2,3,5(包括1和該整數本身)的整數稱為醜數(ugly number)。換句話說醜數ugly_number是可以表示成形如下面表示式的形式,表示式中的i,j,k均是大於等於0的整數。

舉個例子,18 = 2 * 3 * 3,所以18是乙個醜數。而14 = 2 * 7,所以14不是乙個醜數。

現在有個需求就是要找到第2013個醜數。

解決問題的思路顯然是要根據醜數的性質。主要有兩種思考的切入點。

第一種方法,按照整數正好三順序乙個乙個找,並判斷該整數是不是醜數,如果是醜數的個數加1,如果不是繼續查詢下乙個,直到找到問題要求的第n個醜數即可,這種方法的效率不是很好,但是很好理解,所以在這裡只給出偽**。偽**如下:

while(i < n)

if(true == judge_ugly_number(number))

i++;

ugly_numbers[i] = number;

number++;

else

number++;

判斷乙個數是否是醜數的偽**如下:

while(0 == number % 2)

number /= 2;

while(0 == number % 3)

number /= 3;

while(0 == number % 5)

number /= 5;

if(1 == number)

reutrn true;

else

return false;

第二種方法。第一種方法的思路是遍歷整數並判斷該整數是不是醜數。而第二種方法的思路則是根據醜數的性質直接計算醜數。

為實現方便我們可以另ugly_numbers[0] = 1。那麼來計算第乙個醜數,根據醜數的性質,它只含有因數2,3,5所以我們的醜數等於

ugly_numbers[0]乘以這些因數。如果已經求得第i個醜數,那麼怎麼來求第i+1個醜數呢。我們需要找到大於第i個醜數中最小的那個,那麼我們需要在i前面的幾個醜數中分別乘以2,3,5找到那個大於第i個醜數的最小的那個。所以我們還需要保留第i個前面的那幾個醜數的下標。從第乙個醜數開始,如果該醜數是

ugly_numbers * 2,則對2的index1進行加1,

如果該醜數是

ugly_numbers * 3,則對2的index2進行加1

,如果該醜數是

ugly_numbers * 5,則對5的index3進行加1

。要好好分析這句話,

根據計算順序,顯然乙個醜數是2,第二個是3,第三個是4,第四個是5,第五個是6,而6可以

用醜數2乘以因數3得到,也可以用醜數3乘以因數2得到。所以求出醜數六後需要對index1和index2都要進行加1操作。這個敘述的可能不太清楚,請讀者根據後面的程式實現在做進一步理解吧。(如果還不是很清楚的話可以參考後面的參考資料2和3)

第二種方法將給出具體的程式實現,(注意資料型別的選取,防止溢位)。

#include #define max_number 2048

long min(long a, long b, long c)

int main(int argc, char *argv)

printf("please input a integer number,

we'll find the ugly number in that position(number < 2048)\n");

while(eof != (scanf("%d", &position)))

return 0;

}

下面我們來計算一下程式中的for迴圈執行的時間,需要用到time.h,這個的用法還在總結中,總結好會在會c/c++學習中給出來。

下面先給出計算時間函式:

void count_time(struct timespec start, struct timespec end)

else

duration = nanosecond * (int)counttime.tv_sec + counttime.tv_nsec;

printf("compute the ugly numbers took %ld nsec \n",duration);

}

我們回到程式中去測試那個for迴圈的耗時:

clock_gettime(clock_process_cputime_id, &tpstart);

for(; i < max_number; i++)

clock_gettime(clock_process_cputime_id, &tpend);

count_time(tpstart, tpend);

這裡測試5次,可以得出這5次的耗時(單位是納秒):56859,57432,55523,56880,57316,可以計算得出平均耗時為56802。

上述的測試程式中每次都在呼叫min函式,我們現在在這個for迴圈內部實現這個功能並測試其耗時:

clock_gettime(clock_process_cputime_id, &tpstart);

for(; i < max_number; i++)

clock_gettime(clock_process_cputime_id, &tpend);

count_time(tpstart, tpend);

依然測試5次,

可以得出這5次的耗時(單位是納秒):25767,26283,25473,25607,27326,

可以計算得出平均耗時為

26091。

結果很明顯,第二個測試比第乙個測試要省多一半的時間。節省的時間就是每次for迴圈都要呼叫min函式的時間。而且要是考慮空間開銷的話,測試的第二種方法會比較省空間,所以在for迴圈中最好不要頻繁的呼叫乙個實現簡單功能的函式。但是不要以為這個違反了時間複雜度和空間複雜度是一對矛盾體,因為第一種測試中會呼叫乙個額外的函式,所以比較浪費空間,而且每次都呼叫也比較費時。

總的來說,要想提公升時間效率就會需要拿空間來換,要想節約空間就要拿時間來換。

1. more programming perls confessions of a coder, jon bentley

2. google面試題目 尋找醜數--使用double防止資料溢位:

3. 程式設計師面試題精選100題(37)-尋找醜數[演算法]:

說明:

關於程式執行效率的一些想法

今天寫程式的時候我考慮到在乙個for迴圈中加上if判斷的時候效率的問題 迴圈上萬 十萬等數量級的時候 一開始的想法很簡單,就是能不加就不加,儘管不知道會影響多少的效率,但是不加總會比加上要好。正好今晚超哥在,我就請教了一下超哥,其實很簡單,主要看這個迴圈的有效迴圈次數,神馬是有效迴圈次數呢比如 in...

關於提高程式效率的一些建議

關於提高程式效率的一些建議 1 盡量使用編譯時求值的表示式 如常量表示式 而減少使用執行時求值的表示式 代價更高 2 在for迴圈裡減少計數器的使用 可能的話 如下 define size 50 int x size int y size void try sizeof align 則顯示要佔12位...

c語言關於完數(完全數,完美數)的判斷及尋找

c語言關於完數 完全數,完美數 的判斷及尋找 對於乙個 正整數,如果它和除了它自身以外的所有 正因子 之和相等,我們稱它為 完美數 示例 1 輸入 28 28 1 2 4 7 14 1,2,4,7,和 14 是 28 的所有正因子。提示1 num 108 由上定義可知找出某個範圍的完數 includ...