算法習題64:尋找醜數2 3 5的倍數

題目:我們把只包含因子

235的數稱作醜數(Ugly Number)。例如68都是醜數,但14不是,因爲它包含因子7。習慣上我們把1當做是第一個醜數。求按從小到大的順序的第1500個醜數。

--------------------------------

這題目其實類似之前一個統計某個數出現的1的個數,統計n以下所有數出現的1的次數。。

這種題目如果用直接法一般能夠迅速寫出答案,只不過時間上稍微慢點就是了。

換個思路,其實就是要我們找出符合條件的數,然後在對其進行排序,找到第1500是多少。

每次增加的數都是之前數乘以2或者3或者5中最小的數,每次增加都是按照遞增順序增加,所以在第1500個的時候停止就可以了,這裏注意下需要使用long類型

所以很容易寫出下面這段代碼

void Find1(){
	int i=0, idx=0;
	long b0=0,b1=0,b2=0,cand=0;
	long arr[1500];
	arr[0]=1;
	idx=1;
	int j=0;
	while(idx<1500){

		cand=5*arr[idx-1];
		for(j=0;j<idx;j++){//每次都讓之前的數字乘以2 3 5
			b0=2*arr[j];
			b1=3*arr[j];
			b2=5*arr[j];
			if(b0>arr[idx-1] && b0<cand)//篩選出候選值
				cand=b0;
			if(b1>arr[idx-1] && b1<cand)
				cand=b1;
			if(b2>arr[idx-1] && b2<cand)
				cand=b2;
		}
		arr[idx++]=cand;
	}

	//print
	cout<<arr[1499]<<" ";
}

可是,每次循環都是從頭再計算一次,其實很多值是不可能比arr[idx-1]大的,這種結果其實是在浪費計算時間,所以可以加入一個指針指向,排除掉那些乘以2 3 5不可能超過arr[idx-1]的值

這裏需要三個指針指向,分別是2 3 5他們對應的,每次計算arr[j]*2 arr[j]*3 arr[j]*5 發現小於arr[idx-1]那麼對應的指向t0 t1 t2向後移動

更改後代碼如下:

void Find2(){
	int i=0, idx=0;
	long b0=0,b1=0,b2=0,cand=0;
	int t0=0,t1=0,t2=0;
	long arr[1500];
	arr[0]=1;
	idx=1;
	int j=0;
	while(idx<1500){
		cand=5*arr[idx-1];
		for(j=t0;j<idx;j++){
			count++;
			b0=2*arr[j];

			if(b0<=arr[idx-1])
				t0=j+1;
			else{
				if(b0<cand)
					cand=b0;
			}
		}
		for(j=t1;j<idx;j++){
			count++;
			b1=3*arr[j];
			if(b1<=arr[idx-1])
				t1=j+1;
			else{
				if(b1<cand)
					cand=b1;
			}
		}
		for(j=t2;j<idx;j++){
			count++;
			b2=5*arr[j];
			if(b2<=arr[idx-1])
				t2=j+1;
			else{
				if(b2<cand)
					cand=b2;
			}
		}
		arr[idx++]=cand;
	}

	//print
	cout<<arr[1499]<<" ";
}

我比較了下次數,循環次數第一種大約1,124,250次 第二種循環次數則只有580,432次,如果是乘法次數則一種有3,372,750次,第二種還是580,432次,可見這個時間上差很多了,不過還是一瞬間的事啦

計算結果如下:

859963392 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章