前幾天事情比較多,Kata沒有按照一天一個的進度完成。做之前問了一下小伙伴,他說這次是個算法題,挺麻煩。我聽完就是心頭一緊,這才第6個Kata就要搞算法,那后面豈不是沒法做下去了。
直到看完題目我才松了一口氣,以這個作者的尿性就不可能出純算法題嘛!
任務
這次的任務是從一串單詞中找到所有異構單詞。好吧我也不知道這么翻譯對不對,反正化學上學過異構我就叫它異構了。
異構簡單來說就是組成元素相同但是結構不同,比如說fresher和refresh就是一對異構單詞。
我們的目標就是找出輸入單詞中的所有異構單詞。
這題乍一看上去還是挺唬人的,似乎一下就會想到什么公共子序列啊逆序對啊K(看)M(毛)P(片)算法啊這些東西,很遺憾的是這作者裝得不像,還在文章結尾說
大家好我用ruby實現了一個hack版本可以在i7的電腦上1.8秒執行完成哦
我一看這個輸入列表有30W+個單詞,我就明白他啥意思了,這題根本不是算法題,就是個腦筋急轉彎。
思路
思路其實很簡單,關鍵是別掉進算法的圈套。
簡單來說,我們需要一個hash函數,這個函數對于異構單詞的hash結果是相同的,我采用的方法是計算單詞中的所有字符以及每個字符的出現次數,然后用這個信息構建一個字符串當作結果。
舉例來說,fresher中出現了5個字母:fresh,出現次數分別是:12211,我們可以按照字典序構造一個字符串:e2f1h1r2s1,這就是hash結果。我們可以對refresh應用同樣的過程,由于最后會按照字典序排序,所以消除了字符出現位置對結果的影響。
這個函數搞定之后下面就簡單了,直接用結果當作dict的key,value是一個array,存儲這個key對應的所有字符串,這些字符串都是異構的。
代碼
仍然是我喜歡的Python,只有10行哦:
import collections
all_results = {}
with open("wordlist.txt") as f:
for i in f.readlines():
temp = i.strip()
count_list = list(i)
temp_list = list(set(temp))
all_results.setdefault("".join([j + str(count_list.count(j)) for j in temp_list]), []).append(temp)
這段代碼在我的電腦上執行時間大概是3.6秒,不過我的是i5,這段代碼性能瓶頸主要都是CPU運算,所以換成i7的話應該不輸作者的1.8秒。
總結
我最喜歡的就是這類旁門左道,又好玩又高效,何樂而不為呢?不過最近感覺是該撿撿算法了,等21個Kata全部做完就開始做算法題,基礎還是不能丟啊。