1、從300萬字串中找到最熱門的10條
搜尋的輸入資訊是乙個字串,統計300萬輸入資訊中的最熱門的前10條,我們每次輸入的乙個字串為不超過255byte,記憶體使用只有1g。請描述思想,寫出演算法(c語言),空間和時間複雜度。
255位元組*300萬=7,5500,0000位元組=755,000k=755m=0.75g
所以完全可以放入記憶體處理,建立乙個字串的hash陣列,然後遍歷所有字串,相應的加一處理,然後排序即可,演算法負責度極為o(n)
2、如何找出字典中的兄弟單詞。給定乙個單詞a,如果通過交換單詞中字母的順序可以得到另外的單詞b,那麼定義b是a的兄弟單詞。現在給定乙個字典,使用者輸入乙個單詞,如何根據字典找出這個單詞有多少個兄弟單詞?
首先定義乙個key,使得兄弟單詞有相同的key,不是兄弟的單詞有不同的key。例如,將單詞按字母從小到大重新排序後作為其key,比如bad的key為abd,good的key為dgoo。使用鍊錶將所有兄弟單詞串在一起,hash_map的key為單詞的key,value為鍊錶的起始位址。
開始時,先遍歷字典,將每個單詞都按照key加入到對應的鍊錶當中。當需要找兄弟單詞時,只需求取這個單詞的key,然後到hash_map中找到對應的鍊錶即可。
3、找出陣列中出現次數超過一半的數,現在有乙個陣列,已知乙個數出現的次數超過了一半,請用o(n)的複雜度的演算法找出這個數。
答案1:建立乙個hash_map,key為陣列中的數,value為此數出現的次數。遍歷一遍陣列,用hash_map統計每個數出現的次數,並用兩個值儲存目前出現次數最多的數和對應出現的次數。
這樣可以做到o(n)的時間複雜度和o(n)的空間複雜度,滿足題目的要求。
但是沒有利用「乙個數出現的次數超過了一半」這個特點。也許演算法還有提高的空間。
答案2:
使用兩個變數a和b,其中a儲存某個陣列中的數,b用來計數。開始時將b初始化為0。
遍歷陣列,如果b=0,則令a等於當前數,令b等於1;如果當前數與a相同,則b=b+1;如果當前數與a不同,則令b=b-1
。遍歷結束時,a中的數就是要找的數。
這個演算法的時間複雜度是o(n),空間複雜度為o(
1)。1 2 1 3 1 5 4 1 1 1 1 8 9
b=0 b=0 b=0 b=0 b=0 b=0 b=0 b=0 b=1 b=2 b=3 b=2 b=1
a=1 a=2 a=1 a=3 a=1 a=5 a=4 a=1 a=1 a=1 a=1 a=1 a=1
4、找出被修改的數字
n個空間(其中n<1m),存放a到a+n-1的數,位置隨機且數字不重複,a為正且未知。現在第乙個空間的數被誤設定為-1。已經知道被修改的數不是最小的。請找出被修改的數字是多少。
例如:n=6,a=2,原始的串為5,3,7,6,2,4。現在被別人修改為-1,3,7,6,2,4。現在希望找到5。
回答:由於修改的數不是最小的,所以遍歷第二個空間到最後乙個空間可以得到a的值。
a到a+n-1這n個數的和是total=na+(n-1)n/2
。 將第二個至最後乙個空間的數累加獲得sub_total。
那麼被修改的數就是total-sub_total。
5、給40億個不重複的unsigned int的整數,沒排過序的,然後再給幾個數,如何快速判斷這幾個數是否在那40億個數當中?
這是我非常喜歡的一道題。答案: unsigned int的取值範圍是0到2^32-1。我們可以申請連續的2^32/8=512m的記憶體,用每乙個bit對應乙個unsigned int數字。首先將512m記憶體都初始化為0,然後每處理乙個數字就將其對應的bit設定為1。當需要查詢時,直接找到對應bit,看其值是0還是1即可。
6、在乙個檔案中有10g個整數,亂序排列,要求找出中位數。記憶體限制為2g。
回答:不妨假設10g個整數是64bit的。
2g記憶體可以存放256m個64bit整數。
我們可以將64bit的整數空間平均分成256m個取值範圍,用2g的記憶體對每個取值範圍內出現整數個數進行統計。這樣遍歷一邊10g整數後,我們便知道中數在那個範圍內出現,以及這個範圍內總共出現了多少個整數。
如果中數所在範圍出現的整數比較少,我們就可以對這個範圍內的整數進行排序,找到中數。如果這個範圍內出現的整數比較多,我們還可以採用同樣的方法將此範圍再次分成多個更小的範圍(256m=2^28,所以最多需要3次就可以將此範圍縮小到1,也就找到了中數)。
7、將多個集合合併成沒有交集的集合。
給定乙個字串的集合,格式如:,,,,要求將其中交集不為空的集合合併,要求合併完成後的集合之間無交集,例如上例應輸出,,。
(1)請描述你解決這個問題的思路;
(2)請給出主要的處理流程,演算法,以及演算法的複雜度
(3)請描述可能的改進。
回答:集合使用hash_set來表示,這樣合併時間複雜度比較低。
1、給每個集合編號為0,1,2,3
...
2、建立乙個hash_map,key為字串,value為乙個鍊錶,鍊錶節點為字串所在集合的編號。遍歷所有的集合,將字串和對應的集合編號插入到hash_map中去。
3、建立乙個長度等於集合個數的int陣列,表示集合間的合併關係。例如,下標為5的元素值為3,表示將下標為5的集合合併到下標為3的集合中去。開始時將所有值都初始化為-1
,表示集合間沒有互相合併。在集合合併的過程中,我們將所有的字串都合併到編號較小的集合中去。
遍歷第二步中生成的hash_map,對於每個value中的鍊錶,首先找到最小的集合編號(有些集合已經被合併過,需要順著合併關係陣列找到合併後的集合編號),然後將鍊錶中所有編號的集合都合併到編號最小的集合中(通過更改合併關係陣列)。
4、現在合併關係陣列中值為-1的集合即為最終的集合,它的元素**於所有直接或間接指向它的集合。
演算法的複雜度為o(n),其中n為所有集合中的元素個數。
題目中的例子: 0
: 1:
2:
3: 4
: 生成的hash_map,和處理完每個值後的合併關係陣列分別為
aaa:
0。[-1,-1,-1,-1,-1
] bbb:
0,1。[-1,0,-1,-1,-1
] ccc:
0。[-1,0,-1,-1,-1
] ddd:
1,4。[-1,0,-1,-1,0
] eee:
2。[-1,0,-1,-1,0
] fff:
2。[-1,0,-1,-1,0
] ggg:
3。[-1,0,-1,-1,0
] hhh:
4。[-1,0,-1,-1,0
] 所以合併完後有三個集合,第0,
1,4個集合合併到了一起,
常見排序演算法整理
經常忘記簡單的排序演算法,有時間整理下來,便於隨時翻閱,也為了隨用隨取 插入排序演算法 取第乙個數作為有序佇列,從後面的無序佇列中依次取值,在有序佇列中從後向前比較大小,插入到有序佇列中。void insertsort int unsort,int n unsort j temp 選擇排序演算法 與...
javascript 常見演算法整理
字串反轉 因為這個是用的自己的最簡單的方法進行的實現,所以不整理 了 回文 正著讀與反著讀效果一樣,稱為回文 思路 利用陣列的reverse方法,join方法進行拼接,判斷反轉後拼接是否與原資料一致,一致則是回文 出現次數最多的字元 思路 建立乙個物件,然後遍歷字串,字串的每個字元作為物件的key,...
常見加密演算法整理
0x1加密演算法分類 0x11根據加密演算法使用的秘鑰數量,可以將加密體制分為對稱金鑰體制 symmetric cipher,單秘鑰密碼體制,秘密秘鑰密碼體制,對稱秘鑰密碼體制,常規密碼體制 和非對稱秘鑰體制 asymmetric cipher,雙秘鑰密碼體制,公開秘鑰密碼體制,非對稱 密碼體制 對...