从单词统计问题看面试
本文的很多內容來自網絡。如有錯誤,歡迎指出。
問題描寫敘述
?首先這里對單詞的界定是:以空白切割的字符序列。
單詞統計的問題能夠描寫敘述為:在一篇正常格式的英文文檔中(作為面試。這里并沒有提及中文分詞和單詞統計的問題),統計每一個單詞出現的次數。要求統計出現次數最多的N個單詞和對應的出現次數。
問題簡單明了。無需對字面做很多其它的解釋。
為什么面試官都喜歡考諸如此類的問題?
這類問題,大都有一個共同點:不僅要考慮數據的存儲,并且要考慮排序的問題。更重要的是。普通方法能夠解,偏偏面試官要找性能最好的、形式最優雅的。
怎么解?
??? 細致研讀一下題目,發現事實上僅僅有三件事情要做:1.單詞次數統計 2. 排序。
3.輸出前N個,當中問題3僅僅是問題2的衍生,因此能夠忽略。進一步分析發現,事實上這是典型的TOP K問題。拋開TOP K問題的經典解決方式不提,我們先看看一步步來看問題的解決思路。
1. Map
??? C++ Standard Template Library中提供了一種高效的容器Map, 它是一種鍵值對容器(關聯容器),因此能夠輕松存儲<單詞, 次數>這種鍵值序列,因而,最簡潔的解決方式能夠是這種:
int main(void){Map <String , int> wc;Map <String , int>::iterator j;String w;while( cin >> w ){wc[ w ] ++;}for( j = wc.begin(); j != wc.end(); j++ ){count << j->first << " : " j->second << "\n";}return 0; }
因為Map的特性(數據插入時保證有序),因此輸出的結果事實上是依照key(也就是單詞)排好序的。所以,還須要對輸出的結果進行排序。至于怎么排序,sort。qsort,還是自建heap sort。不再贅述。
這樣已經非常好了,Map容器本身內建紅黑樹,使得插入的效率非常高。
可是,這樣真的好嗎?別忘了,面試官的要求更高。
2. Hashtable 神器。一鍵直達。效率再快一點
對于單詞和單詞次數的映射,除了使用Map外,還能夠使用自己定義的hash表,hash表的節點應該包含三個主要的域:指向單詞的指針或String,單詞的出現次數int。指向下一個節點的指針node *。
如果我們處理hash沖突的方案是鏈地址法。則:
Hash表node的定義為:
typedef struct node{char * word;int count;node * next; } node;
再次如果,處理的獨立的單詞個數不超過5w, 因此能夠選擇50021?這個質數作為hash表的大小。而hash算法。我們能夠選擇經常使用的BKDR算法(以31為累乘因子),這樣。能夠將單詞映射為一個unsigned int的整數:
#define HASH_SIZE 50021; #define MUL_FACTOR 31; node* mmap[HASH_SIZE];unsigned int hashCode( char *p){unsigned int result = 0;while(*p != '\0' ){result = result * MUL_FACTOR + *p++;}return result % HASH_SIZE; }
??? 函數wordCount( char *p )用于將單詞和單詞的出現次數插入hash表中,假設hash表中有對應的節點,則添加單詞的次數并返回,否則須要加入新的節點到hash表的表頭并初始化次數為1.
1 void wordCount( char *w ){ 2 unsigned int hashCode = hash( p ); 3 node * p; 4 5 while( p = mmap[hashCode];p!=NULL;p = p->next ){ 6 if(strcmp(w, p->word) == 0){ 7 (p->count)++; 8 return ; 9 } 10 } 11 12 node*q = (node*) malloc(sizeof(node)); 13 q->count = 1; 14 q->word = (char *) malloc(sizeof(w) + 1); 15 strcpy(q->word, w); 16 q->next = mmap[hashCode]; 17 mmap[hashCode] = q; 18 }
相同,hash表僅僅是提供了數據存儲。并沒有排序。排序的問題,還須要你來完畢。
這樣似乎就完美了。
可素。倫家既不懂算法,又不會C++的容器。腫么辦 ?
3.? Shell版本號的單詞統計
Linux提供了非常多文本操作的工具。比方uniq, tr ,sort。而管道的存在,恰到優點的攻克了文本和單詞及中間處理結果須要存儲的問題。最重要的一點,這些工具是一系列的黑盒,你僅僅須要知道怎樣使用,而大不必去在乎內部實現的細節。
對于本題。用Linux 工具去處理,命令能夠是:
cat word | tr –cs a-zA-Z\’ ‘\n’ | tr A-Z a-z | sort | uniq –c | sort –k1,1nr | head –n 10
?對該程序每一行的解釋:
- cat word ? ???????????? 將word文件的內容讀入緩存區。并作為下一個命令的輸入
- tr –cs a-zA-Z\’ ‘\n’ ? 將非字母字符轉換為換行符,保證一行一個單詞
- tr A-Z a-z ???????????? 將全部單詞轉為小寫形式。保證and和And是同一個單詞
- sort? ???????????????????? 按單詞排序
- uniq –c ???????????????? 統計每一個單詞的反復次數,也就相當于單詞的出現次數
- sort –k1,1nr ? ???????? 依照出現次數排序逆序排序。-n指定數字比較。-r指定逆序排序
- head –n 10 ? ? ??????? 輸出出現次數最多的10個單詞和它們的出現次數
寫到這里,突然想起若干年前去百度面試的時候。一個技術T5的大拿問的問題,也就是這道單詞統計的問題:一個文本中包括了非常多單詞,每行一個單詞,怎樣統計每一個單詞的次數?極其小白的我毫不含糊的回答:PHP腳本中每次讀一行。用關聯數組存單詞和單詞次數…….結果必定是慘烈的。
4.??? 文本處理的利器-AWK
既然提到了linux工具,那就不得不提一下awk(?k), awk是一個強大的文本分析處理工具。
Wiki上如是說:
??? AWK是一種優良的文本處理工具,Linux及Unix環境中現有的功能最強大的數據處理引擎之中的一個。AWK提供了極其強大的功能:能夠進行正則表達式的匹配。樣式裝入、流控制、數學運算符、進程控制語句甚至于內置的變量和函數。
它具備了一個完整的語言所應具有的差點兒全部精美特性。
??? 盡管僅是溢美之詞,可是不得不承認awk確實非常強大。
awk -F ' |,' '{for(i=1; i<=NF;i++){a[tolower($i)]++;} }END{for(i in a)print i, a[i] |"sort -k2,2nr"; }' word
???? gawk 3.1+中。能夠使用內置函數asort和asorti對數組進行排序,只是排序的功能較弱。
比如asort(a) ,若a是關聯數組。asort的行為是僅僅對值排序,而鍵將被丟棄,取而代之的是新的1-n的數字索引。這能夠通過自己定義排序函數的方式或者結果通過管道傳遞給系統sort排序解決。
5.?? 數據庫版本號的方案。
我們這里如果文本已經是一行一個單詞。
數據庫表的基本結構為:
CREATE TABLE `test` (`word` varchar(20) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=gbk;
單詞入庫(也能夠load data in file):
awk ' BEGIN{sql="insert into test(word) values ";mysql="mysql -hxxxxxx -uxxxxx -pxxx test -e "; }{for(i=1;i<=NF;i++){sq="\"" sql "('\''" $i"'\'')" "\"";print mysql sq |"sh -x";} }' word
那么簡單的查詢:
select word,count(word) as total from test group by word order by total desc;
就能夠得到單詞的次數。
這樣的方法非常easy,由于數據庫替你完畢了全部統計和排序的工作,這也是為什么非常多人一旦有什么需求就求助于數據庫。
基于Key-Value的緩存系統(Redis等)也能夠完畢排序的功能。這里不再贅述。
思考
??? 假設你是面試官。你看好哪一種解法?算法和數據結構的。還是shell的,awk的。
就我而言,我覺得面試是挑選人才的。而不是靠所謂的“奇技淫巧”去為難別人的。
假設是我,看到有人用了shell的方式,或者awk的方式。我會給他高分。盡管算法是王道,但真的須要“一切從源代碼做起”么?
?
參考文獻:
1. http://www.cnblogs.com/ggjucheng/archive/2013/01/13/2858470.html
2.《shell腳本指南》
3.《編程珠璣》
轉載于:https://www.cnblogs.com/gccbuaa/p/7172407.html
總結
以上是生活随笔為你收集整理的从单词统计问题看面试的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 最全正則表達式汇总—想要的都有了
- 下一篇: pip飞起来了