把只包含因子2、3和5的數稱作醜數(ugly number)。例如6、8都是醜數,但14不是,因為它包含因子7。 習慣上我們把1當做是第乙個醜數。求按從小到大的順序的第n個醜數。
對於這個問題,最容易想的就是乙個個數進行判斷,
如:
public
static
intgetuglynumber(int index)
}i++;}}
public
static
boolean
isuglynumber(int number)
if(number == 1)else
}
index = 100
1536
678.071ms
index = 1000
51200000
2545589.285ms
儲存所有檢測過的資料,並且採用hash表
setset = new hashset();
if(index == 1)
set.add(1);
int i = 2;
int count = 1;
while(true)else
if((i % 3 == 0) && set.contains(i/3))else
if((i % 5 == 0) && set.contains(i/5))
if(count == index )
i++;
}
index = 100
1536
1745.431ms(甚至還不如第一種,hashset預設是16,所以需要不停的擴容)
index = 1000
51200000
2401278.071ms(初始指定容量為20480時,效果較明顯)
指定hashset初始容量為20480
index = 100
1536
2340.335ms
index = 1000
51200000
1875198.538ms
但是依然令人不滿意,那麼有沒有更好的方法呢?
第一種:需要對每乙個數都進行判斷,而當index很大時,判斷函式消耗了太多的無用時間
第二種:雖然利用了先前的計算結果,但是hash表的擴容操作會是乙個很耗時間的操作,儘管我們看不到;
那麼是否可以利用先前的結果,而又避免擴容呢?
假設array裡已經儲存了n個醜數(已經按大小排好序),那麼第n+1個醜數一定是前面所有醜數乘以2,乘以3,乘以5的最小值,這是一定的,因為醜數一定是醜數的乘積。其次為了保持陣列的順序,所以選擇最小值。
如果遍歷n個數,然後分別乘以2,3,5,計算最小值,將又會是o(n^2)的操作。
由於陣列排好序了,設最大值為m,那麼存在乙個位置flag2,使得array[flag2]*2大於m,而array[flag2-1]*2小於等於m,同理對於位置flag3,位置flag5也有這個性質
因此為了計算第n+1個醜數,只需要計算min
public
static
intgetuglynumber2(int index)
int ugly = new
int[index];
ugly[0] = 1;
int count = 1;
int flag2 = 0;//flag2*2大於ugly[count-1]
int flag3 = 0;//flag3*3大於ugly[count-1]
int flag5 = 0;//flag5*5大於ugly[count-1]
while(count < index)
if(ugly[flag3]*3
<= ugly[count])
if(ugly[flag5]*5
<= ugly[count])
count++;
}return ugly[index-1];
}
index = 100:
1536
196.414ms
index = 1000:
51200000
292.321ms
改變非常明顯
劍指offer 醜數
把只包含因子2 3和5的數稱作醜數 ugly number 例如6 8都是醜數,但14不是,因為它包含因子7。習慣上我們把1當做是第乙個醜數。求按從小到大的順序的第n個醜數。分析 參考程式設計師面試金典 偽 如下 1 初始化array和佇列 q2 q3 q5 2 將1插入array 3 分別將1 2...
劍指Offer 醜數
我們把只包含因子 2 3 和 5 的數稱作醜數 ugly number 求按從小 到大的順序的第 1500 個醜數。例如 6 8都是醜數,但 14 不是,它包含因子 7。習慣上我們把 1當做第乙個醜數。解法一 逐一判斷是否是醜數,簡單但是不夠高效 數字n是數字m的因子說明m n 0。醜數的因子只有2...
劍指offer 醜數
把只包含因子2 3和5的數稱作醜數 ugly number 例如6 8都是醜數,但14不是,因為它包含因子7。習慣上我們把1當做是第乙個醜數。求按從小到大的順序的第n個醜數。分析 為了保證時間達到要求,可以將所求得的醜數都儲存在陣列中,然後再取出。前面的醜數乘以2 3或5中的最小的乙個是下乙個醜數。...