今天學習了Python的列表內涵(List comprehension,也有譯為列表推導式的),對這個東西有點著了魔。正好看到了園子裡木野狐用Python求解雙倍超立方數計算的文章(也玩有道難題的雙立方數問題:Python 版解法),就跟著學了做了一個。
這道題目的要求是:雙倍超立方數是指一個正整數可以正好被拆分為兩種不同的a^3+b^3的方式,其中a,b均為整數且0<a<=b。對於任何一個指定的 int n, 返回所有的小於等於n的雙倍超立方數的個數。
我解題的演算法思路是和木野狐以及yujiasw的《有道難題的雙立方數問題的高速解法》學的,不過這個Python代碼為了減少行數,有很多地方沒有最佳化,效率不高(裝B害死人啊)。
二話不說,上代碼先:
print len([1 for a in [x+y for x,y in [(k,j) for k in [i**3 for i in xrange(int(round(pow(100000, 1./3))))] for j in [i**3 for i in xrange(int(round(pow(100000, 1./3))))] if k <= j]] if [x+y for x,y in [(k,j) for k in [i**3 for i in xrange(int(round(pow(100000, 1./3))))] for j in [i**3 for i in xrange(int(round(pow(100000, 1./3))))] if k <= j]].count(a)==2])/2
看看,是一行吧!這一行代碼的功能就是把100000之內符合以上要求的數字個數列印出來。運行一下,結果肯定是對的(不信你試一下,建議把100000改為10000)。不過我估計能讀懂這行代碼的地球人不多啊。我10分鐘前寫好的,現在自己也讀不懂了 囧! (我是先寫好每層迴圈,然後一層一層套成了一個List comprehension)。
寫以上代碼是為了說明Python不僅可以把複雜問題簡單化,也能把簡單問題複雜化:)。
下邊這個版本就易讀多了:
#coding: utf-8
n = 10000 #計算的最大數上限n
cubes = [i**3 for i in xrange(int(round(pow(n, 1./3))))] #產生小於n的所有立方數
sum = [x+y for x,y in #將立方數二元組相加,得到所有超立方數
[(k,j) #得到所有立方數兩兩組成的二元組
for k in cubes #外層迴圈
for j in cubes #內層迴圈
if k <= j #此處沒有最佳化,共迴圈了k^2次,實際上有k(k+1)/2次就夠了
]
]
print len([1 #這行代碼實際上效率很低,應用dict改為hash尋找
for a in sum #在列表中遍曆所有的超立方數,
if sum.count(a)==2 #如果某個數值出現了兩次,說明它是一個雙倍超立方數
])/2 #所有超立方數構成的列表長度除2就是雙倍超立方數個數,列印輸出它
看來列表內涵可以用,但絕對不能濫用。適當使用還是可以提高工作效率的,如果像我這樣濫用,就會適得其反。
至於具體的Python列表內涵使用方法,網上這方面的文章很多,我就不重複介紹了。如果感興趣,我向你推薦《可愛的 Python:Python 中的函數編程》,關於Python列表內涵很不錯的一篇文章。