題目:我們把只包含因子
2、3和5的數稱作醜數(Ugly Number)。例如6、8都是醜數,但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