華爲編程面試題目 求2到2000的質數 源程序

內存足夠大,寫程序輸出2到2000的質數。

'''華爲面試題目 求2到2000的質數'''
N = 2000
number = list( range(2, N+1) )
times = 0
checknum = list(range(2,int((N+1)/2)+1))
for i in checknum:
    for index in number:
        times += 1
        if index != i:
            if index/i == int(index/i):
                number.remove(index)
                if index in checknum:
                    checknum.remove(index)

print(number)
print("嘗試%d次"%times)

以上比較樸素、比較笨、比較快速的實現了一個程序。如果作爲本科生,寫出這樣的程序或可以接受。

設計思想:

驗證一個大於2的數是不是質數,當然只要從2循環到int(N/2),去除這個數,如果能夠整除,被除數不等於除數,則這就是一個合數。如果都不能整除,則這是一個質數。

但是如果從2一直到N,都這樣求一遍,時間複雜度太高了。比如,計算49是不是質數,前面會使用4和6去除,問題是4和6本身就是合數,其實應該使用質數去除49驗證,也就是用2 3 5 7,但是,怎麼直接拿這種質數去除呢?那麼以上程序的樸素思想1就來了:維護兩個表,一個表number是從2到N,一個表checknum是從2到N/2,checknum專門存儲除數。每一次取除數都從checknum取,一旦checknum能夠整除number,判斷出這個number是一個合數,就把它從兩個表裏面刪去。由於我們使用的是python的for in 形式的循環,動態修改循環列表,可以保證目前用於檢查的數是個質數,不會從未來的表裏刪掉。比如我們驗證4/2,則4應該從checknum表裏面刪掉;而不會因爲驗證一個m,導致了小於m的數從number被刪掉,這樣的話,不會需要回溯數組。於是就有了以上程序。

當然這個程序並不是某一種最優解,需要考慮優化解法。

 

有一種獲取一個範圍內的質數的方案叫“篩法”,就是把這個範圍內的數都寫出來,用最小的質數2來除,除盡就劃掉。再用下一個質數3來除,除盡就劃掉。那麼利用這種思想,我們可以有第2種程序:

從list裏面取除數,從2開始,一個個循環去除list包含的元素,查找list中的合數,找到合數就從list刪掉(當然你要考慮到,list的查找+刪除remove函數由於做了大量的數據位移,實際是很耗時的),然後,list的下一個數:3。當3篩過之後,由於4已經在除以2的一輪中刪掉了,所以下一個除數是5。這就避免了使用合數來除list中的數。

另外,用2到N/2中所有的質數來除嗎?也不是。顯然,實際應該從2到int(sqrt(N))來除。比如,N=100,由於除以7的時候,7*14=98已經被刪除,在這之前的7*11=77也被刪除了,已經不需要使用int(sqrt(100))+1=11除了,11*8 11*9 都在更早被刪除,所以只要小於等於10,就可以了。爲什麼要等於?比如N=121,int(sqrt(N))=11,需要除到11時才能把121去掉。

那麼我們就有了下面的解法:

'''華爲面試題目 求2到2000的質數'''
import math
N = 2000
number = list( range(2, N+1) )
times = 0
index = 0 #index表示現在的除數是list裏的第幾個數
flag = int(math.sqrt(N))
for i in number:
    x = number[index]
    if x > flag:break
    for bei in number[index+1:]:
        times += 1
        if bei/x == int(bei/x):
            number.remove(bei)
    index += 1
print(number)
print("嘗試%d次"%times)

這個解法還有沒有改進空間呢?還是有的。在for bei in  number[index+1:]這裏,這是做了一個列表的切片。每做一個切片就是複製數組的一段,還是有比較大的開銷。那麼,我們如果把這個循環換成:自index+1到len(number)循環,取number變量的事情放在裏面,則會省去一些數組複製的空間開銷。

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