python七巧板 解決七巧板時出現記憶體錯誤

2021-10-11 10:06:46 字數 3628 閱讀 5336

我正在嘗試解決以下問題:

字謎是一種文字遊戲,其結果是重新排列單詞或短語的字母以產生乙個新單詞或短語,而所有原始字母恰好使用一次。例如,樂團=馬車。使用上的單詞列表,編寫乙個程式,以查詢共享相同字元且包含最多單詞的單詞集。

即使只有1000位元組的檔案大小,它也會失敗。而且每次建立新列表時,python為什麼將舊列表儲存在記憶體中?我收到以下錯誤。

l=list(map(''.join,itertools.permutations(i)))

給我:memoryerror

這是我的**:

importitertoolsdefanagram():f=open('unixdict.txt')f2=open('result_anagram.txt','w')words=f.read(1000).split('\n')foriinwords:l=l=list(map(''.join,itertools.permutations(i)))l.remove(i)foranagraminl:ifl==i:f2.write(i+"\n")returntrueanagram()

根據建議將以上**更改為。但是仍然出現記憶體錯誤。

importitertoolsdefanagram():f=open('unixdict.txt')f2=open('result_anagram.txt','w')words=set(line.rstrip('\n')forlineinf)foriinwords:l=map(''.join,itertools.permutations(i))l=(xforxinlifx!=i)foranagraminl:ifanagraminwords:f2.write(i+"\n")returntrueanagram()

memoryerror [在22.2秒內完成]

解決方案

無論您做什麼,該程式都將效率極低。

但是您可以解決此問題,memoryerror以便永遠執行而不是失敗。

首先,請注意,乙個12個字母的單詞具有479,001,600個排列。將所有這些儲存在記憶體中將占用2gb以上的記憶體。那麼,您如何解決呢?只是不要將它們全部儲存在記憶體中。將迭代器保留為迭代器而不是建立列表,然後只需要一次容納乙個,而不是全部都適合。

這裡有乙個問題:您實際上是在該if l==i:行中使用該列表。但這顯然是乙個錯誤。字串列表永遠不可能等於單個字串。您最好用替換該行raise typeerror,這時您可以替換整個迴圈,並且可以更快地失敗。:)

我想你想在那裡if anagram in words:。在這種情況下l,除了在for迴圈中,您不需要,這意味著您可以放心地將其保留為惰性迭代器:

foriinwords:l=map(''.join,itertools.permutations(i))l=(xforxinlifx!=i)foranagraminl:ifanagraminwords:f2.write(i+"\n")

我在這裡假設使用python 3.x,因為否則list完全不需要呼叫。如果您使用的是2.x,則將其替換map為itertools.imap。

因此,f.readlines(1000)將使您一次讀取大約1k的緩衝區,而不會出現區域性行。當然,現在,不必split去換行了,您必須去換行rstrip:

words=[line.rstrip('\n')forlineinf.readlines(1000)]

但是,您還有另乙個問題。如果您一次只能讀約100個單詞,那麼找到字謎的機會就很小。例如,orchestra不會carthorse在字典中的任何地方出現,因此除非您記得整個檔案,否則無法找到。但這應該沒問題;典型的unix字典(例如web2)大約有20萬行;您可以輕鬆地將其讀取到記憶體中,並將其保留為set2gb,甚至不會造成任何損失。所以:

words=set(line.rstrip('\n')forlineinf)

另外,請注意,您正在嘗試列印出字典中帶有七字謎的每個單詞(如果有多個七字謎,請多次列印)。即使使用高效的演算法,這也將花費很長的時間,並且會噴出比您可能想要的更多的資料。乙個更有用的程式可能是接受輸入單詞(例如,通過input或sys.ar**[1])並僅輸出該單詞的字謎的程式。

最後:即使使用l作為生成器,它也占用了太多的關閉時間,儘管不會因記憶體錯誤而失敗。您能否解釋單詞作為乙個集合而不是乙個列表的重要性。[在137.4s中完成]僅用於200個位元組,您之前已經提到過,但是如何使用設定的單詞克服它?

正如我在頂部說的那樣:「無論您做什麼,該程式都將效率極低。」

為了找到乙個12個字母的單詞的字母拼寫,您需要進行4.79億個排列,並對照大約20萬個單詞的字典檢查每個單詞,因此每個單詞的479m * 200k = 95萬億個支票。有兩種方法可以改善這種情況,第一種涉及為作業使用正確的資料結構,第二種涉及為作業使用正確的演算法。

將要從列表中迭代的事物集合更改為生成器(惰性可迭代),會將占用線性空間(479m字串)的內容轉換為占用恆定空間的內容(某個固定大小的迭代器狀態,一次新增乙個字串) 。類似地,將要檢查的單詞集合從列表更改為集合,會將花費線性時間(將字串與列表中的每個元素進行比較)變成花費恆定時間(雜湊字串,然後檢視其中是否有內容)具有該雜湊值的集合)。因此,這消除了* 200k問題的一部分。

但是,您仍然可以479m解決問題。而且,您無法通過更好的資料結構來消除這種情況。相反,您必須重新考慮問題。如何在不嘗試所有排列的情況下檢查單詞的任何排列是否與其他單詞匹配?

好吧,當且僅當x和y具有相同的字母時,單詞x的某些排列才與單詞y匹配。x中字母的順序無關緊要;如果集合相同,則至少有乙個匹配的排列(或精確到乙個,取決於您對重複字母的計數方式),否則,則有恰好為0。因此,與其遍歷單詞中的所有排列為查詢,只是查詢其設定。但是,是否存在重複並不重要,因此您不能僅set在此處使用。您可以使用某種多集(collections.counter)作品…或者,在效率上損失很小,而簡單性卻大大提高的情況下,您可以對字母進行排序。畢竟,如果兩個單詞以任意順序具有相同的字母,則當它們都進行排序時,它們的字母將具有相同的順序。

當然,你需要知道哪些詞是字謎,不只是有是乙個字謎,所以你不能僅僅看它在一組字母集,你必須看它在那封信集對映到字的字典。例如,如下所示:

lettersets=collections.defaultdict(set)forwordinwords:lettersets[''.join(sorted(word))].add(word)

因此,現在,要查詢單詞的字謎,您要做的就是:

anagrams=lettersets[''.join(sorted(word))]

它不僅簡單易讀,而且是固定時間的。

而且,如果您真的想列印出所有單詞的所有字謎的龐大列表,那麼,這也很容易:

for_,wordsinlettersets.items():forwordinwords:print('{} is an anagram of {}'.format(word,', '.join(words-)))

現在,與其花費479m * 200k的時間來查詢乙個單詞的字謎,或花費479m * 200k * 200k的時間來查詢所有單詞的字謎,不如花費乙個恆定的時間來查詢乙個單詞的字謎,或花費200k的時間來查詢單詞的所有字謎。所有的話。(當然,建立對映需要在開始時新增200k的設定時間,但是預先花費200k的時間來節省200k,少得多的479m * 200k,每次查詢的時間顯然是乙個勝利。)

當您想要進行某些操作時,事情變得有些棘手,例如,找到部分字謎或句子anagarms,但是您想要遵循相同的基本原理:找到可以在恆定或對數時間內而不是線性或更糟糕的時間內進行操作的資料結構,以及查詢不需要您通過指數或階乘候選數來蠻橫行事的演算法。

Android Canvas繪製七巧板

心血來潮,封裝了乙個繪製彩色多邊形的方法,並用這個方法繪製了乙個七巧板 感覺繪製華容道太簡單了 如下 public class canvaspuzzle extends view public canvaspuzzle context context,attributeset attrs publi...

用python畫七巧板 canvas繪製七巧板

效果如下所示 分享 canvas七巧板 var tangram color caff67 color 67becf color ef3d61 color f9f51a color a594c0 color fa8ecc color f6ca29 定義乙個存放繪製路徑和顏色的陣列 window.nl ...

Canvas學習記錄繪製七巧板 01

lang en charset utf 8 titletitle canvas style head canvas 您的瀏覽器不支援 html5 canvas 標籤,換個瀏覽器試試.canvas window.onload color fe665b color 03a697 color ec3c60...