算法分析---尋找丑數


什么是丑數:

一個數的因子僅僅包括2,3,5的數稱為丑數。數字1特別對待也看作是丑數,所以從1開始的10個丑數分別為1,2。3。4,5,6,8,9。10。12。


因子的概念:

整數m除以n,得到無余數的商,則稱n是m的一個因子。如8的因子有1、2、4、8。而丑數要求的因子僅僅包括2、3、5。所以丑數中的因子應理解為質因子。

即因子為質數。質數又稱素數,指一個大於1的自然數。除了1和它自身外,不能被其它自然數整除的數。

與質數相相應的數稱為合數。

如今要求寫一個程序,輸出從1開始的第N個丑數。

如第一個丑數為1,第二個丑數為2。第十個丑數為12


推斷是否是丑數的算法

設待推斷整數位M,M循環除以2直到不能整除。此時接着循環除以3直到不能整除。接着循環除以5直到商為1或者不能整除為止。

商為1且余數為0則為丑數,否則為非丑數。

如:丑數12

12/2 = 6

6/2 = 3;

3/2 不能整除

3/3 = 1; 結束,12是丑數


非丑數26

26/2 = 13

13/2 不能整除

13/3 不能整除

13/5 不能整除

結束,26不是整數


尋找丑數算法1:

(1)設置一個計數器用來統計出現的丑數的個數

(2)從1開始遍歷每個整數,推斷是否是丑數,假設是丑數則計數器加1。否則遍歷下一個整數。

(3)當計數器的值=N時,停止遍歷。輸出丑數。

#include <stdio.h>
#include <time.h>
#include <string.h>

int isUgly(int number){ //推斷number是否是丑數
	while(number%2==0){ //推斷數是否能被2整除
		number=number/2; 
	}

	while(number%3==0){ //推斷數是否能被3整除
		number=number/3;
	}

	while(number%5==0){ //推斷數是否能被5整除
		number=number/5;
	}
	
	if(number == 1) //
		return 1;
	else
		return 0;
}

int findUgly(int N){  //尋找從1開始的第N個丑數
	int count=0; //用於計數
	int number=1; //從1開始遍歷
	while(1){
		if(isUgly(number)){  //假設number是丑數計數器加1
			count++;
		}
		if(count == N)  //找到第N個丑數,返回丑數
			return number;
		else
			number++; 
	}
}

void main(){
	int N=0;
	scanf("%d",&N);
	clock_t start = clock();
	printf("%d\n",findUgly(N));
	clock_t stop = clock();
	printf("耗時:%lf\n",(double)(stop - start) / CLOCKS_PER_SEC);
}

上面算法從1開始遍歷,來尋找第N個丑數,當N非常大時花費的時間會非常多。當N為1400的時候消耗23秒。隨着N的增大。耗時相當嚴重



尋找丑數算法2:

想辦法從上一個丑數判斷出下一個丑數,而不須要從1開始遍歷再判斷。從1開始的10個丑數分別為1,2。3,4,5,6,8。9。10。12。

能夠發現除了1以外。丑數都是由某個丑數*2或者*3或者*5得到的。

如2是丑數1*2得到的,3是丑數1*3得到的。4是丑數1*4得到的。5是丑數1*5得到的。6是丑數2*3得到的……

詳細算法步驟:

(1)從第一個丑數1開始,求出1*2=2 ,1*3=3 ,1*5 = 5。

(2)取上面乘積中大於1的最小值2,作為第二個丑數(丑數是個遞增序列。所以第i+1個丑數一定比第i個丑數)

(3)求丑數2之前的丑數與2、3、5的乘積:1*2=2 ,1*3=3 ,1*5 = 5; 2*2 = 4; 2*3 = 6。 2*5 =10。

(4)取上面乘積中大於2的最小值3,作為第三個丑數

       ……

       ……

(i)取出丑數i之前的丑數分別與2、3、5的乘積

(i+1)取乘積中大於i的最小值作為丑數

(i+2)反復(i)(i+1)的步驟直到計數器等於N

#include <stdio.h>
#include <time.h>
#include <string.h>

#define MaxLen 99999

//用於求出3個數的最小值
int compare(int chenTwo,int chenThree,int chenFive){
	if(chenTwo <=chenThree){
		if(chenTwo <= chenFive)
			return chenTwo;
		else
			return chenFive;
	}
	else if(chenThree <= chenFive)
		return chenThree;
	else
		return chenFive;
}

//找出第N個丑數
int findUgly(int N){
	int ugly[MaxLen]={1}; //用於保存丑數的數組,將丑數1存入數組中
	int count=1; //數組中僅有丑數1,所以計數器為1

	while(1){
		int chenTwo = 0;
		int chenThree = 0;
		int chenFive = 0;

		/*
			ugly數組中最新的一個丑數為ugly[count-1],
			ugly[count-1]之前的丑數與2相乘,
			求出第一個乘積大於ugly[count-1]的值保存在chenTwo中
		*/
		for(int i = 0 ; i < count ; i++){ 
			if(ugly[i]*2 >ugly[count-1]){
				chenTwo = ugly[i]*2;
				break;
			}
		}

		/*
			ugly數組中最新的一個丑數為ugly[count-1],
			ugly[count-1]之前的丑數與3相乘,
			求出第一個乘積大於ugly[count-1]的值保存在chenThree中
		*/
		for(i = 0 ; i < count ; i++){
			if(ugly[i]*3 >ugly[count-1]){
				chenThree = ugly[i]*3;
				break;
			}
		}

		/*
			ugly數組中最新的一個丑數為ugly[count-1],
			ugly[count-1]之前的丑數與5相乘,
			求出第一個乘積大於ugly[count-1]的值保存在chenFive中
		*/
		for(i = 0 ; i < count ; i++){
			if(ugly[i]*5 >ugly[count-1]){
				chenFive = ugly[i]*5;
				break;
			}
		}

		//chenTwo,chenThree。chenFive的最小值為新的丑數,存入ugly數組中
		ugly[count]=compare( chenTwo, chenThree, chenFive);
		count++;
		if(count==N) //第N個丑數
			return ugly[count-1];
	}
}

void main(){
	int N=0;
	scanf("%d",&N);
	clock_t start = clock();
	printf("%d\n",findUgly(N));
	clock_t stop = clock();
	printf("耗時:%lf\n",(double)(stop - start) / CLOCKS_PER_SEC);
}

當輸入N=1400時,耗時還不足0.1秒。可見算法2的速度是算法1所不能比擬的,這是用空間來換取效率的結果。





免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM