做者:林冠宏 / 指尖下的幽靈java
掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8git
博客:http://www.cnblogs.com/linguanh/程序員
GitHub : https://github.com/af913337456/github
騰訊雲專欄: https://cloud.tencent.com/developer/user/1148436/activities面試
僅列舉一些解決方法,事實的解決方案是很是多的。
這些問題都是面臨着有以下的考慮:算法
若是能把這些問題答好,必然是綜合計算機各方面的知識,從內存到數據結構甚至還涉及到硬件,方法面面。至此,我給它定位是,綜合考量一個程序員計算機基礎能力的面試題。數組
在2.5億
個正整數
中找出不重複的整數。數據結構
分治法 + HashMap
(HashMap 不要侷限在 Java 語言)將 2.5 億個整數,分批操做,例如分紅 250 萬一批,共100批次。每批使用循環遍歷一次,存入 HashMap<int1,int2>
裏面,int1
對應這個數,int2
對應它出現的次數,沒出現就默認是 1 次。每操做完一批,就進行當前的 HashMap
的去重操做
,讀出 int2 > 1
的,排除掉。接下來的批次,以此類推,得出 100,剩下的天然就是不重複的。函數
時間
& 空間
時間複雜度
:250W * 100輪 + 其它批次
。對於多核機器,能夠啓動線程操做。spa
空間複雜度
:使用 int 來進行存每個數,保證不溢出狀況下,那麼就是 --> Key + Value : (250W * 4字節,4Byte)/(1024*1024) ~ (Key + 9.5MB)
內存。
位圖法 Bitmap
(一個 bit 僅會是 0 或 1)對於此題,咱們能夠設計每兩個 bit
位,標示一個數的出現狀況。00
表示沒有出現,01
表示出現一次,10
表示出現屢次。2.5 億個正整數,首先咱們要知道是正整數
,咱們就不須要考慮負數,也就是無符號,無符號的整形佔四個字節
。
位圖
內存。1B = 8b,4B = 32b,它能夠表示的最大
的整數是 2^32-1(不溢出)
,也就是說,咱們須要 2^32-1 ~ 2^32
個位
來表示這2.5
億個數。咱們上面說了,每一個狀態
是兩個位
,那麼總共就是2^32*2
個位。
那麼咱們能夠一次申請的 位圖 內存是:2^32*2 bit ,(2^32*2)/(1024*1024*8) = 1GB
便可。固然,咱們也能夠加上分治
的思路,分批處理,不用直接用 1G,哈哈。
那麼這樣作的狀況下怎樣找到這個數呢?我舉個例子,例如咱們此時讀入一個數是:64
,64
對應的所在bit
位是:64*2=128
,也就是說第 127
和 128
位共同標示了它的出現狀態
。其餘的以此類推。每當咱們讀出一個數,咱們就這樣去找到它對應的bit位
,先讀出bit位
的值,再作記錄,已是01
的,再次來到,那麼就應該修改成10
。最後的咱們這樣得出結果:掃描整個位圖,若是是10
的,就下標/2
得出這個數。
第一題:找出一篇文章中,出現次數最多的單詞。
第二題:10億個正整數
找出重複次數最多的100個整數。
分治法 + HashMap
沒錯,分治法 + HashMap
這個方法就是能夠用來處理不少 Top K
問題的。
對於問題一
,其實比較簡單,這道題也是我 2016 年騰訊第三輪技術面要求當場寫代碼的題目
。咱們能夠先判斷,這篇文章可能很長,也可能很短,那麼咱們應該規定一個字數的標誌
,做爲一批的字數限制,例如100
個文字。每100
個文字是一批的處理極限,咱們先讀出100
個,100之內的就直接所有讀出。讀出後,打散成字符串,例如英語文章它以空格和一些符號分割。使用split
方法就能夠打散。此時咱們得出一個字符串數組String[] array
,有了這個以後就能夠參考 找出不重複
問題的解法。每批使用循環遍歷一次,存入 HashMap<String,Integer>
裏面,string
對應這個數的字符串,Integer
對應它出現的次數,最後最大的天然就是出現次數最多的。下面直接給出個 Demo 函數
。
// LinGuanHong
public static void search(String limitText){
String maxWord = "";
int maxTime = 0;
String[] words = limitText.split(" |\\.|,");
int length = words.length;
HashMap<String,Integer> one = new HashMap<>();
for(int j=0;j<length;j++){
Integer number = one.get(words[j]);
if(number != null){
number = number + 1;
/** 找到次數加 1 */
one.put(words[j],number);
if(maxTime < number){
maxTime = number;
maxWord = words[j];
}
}else{
/** 沒找到,賦值 1 */
one.put(words[j],1);
}
}
System.out.println("maxTime is :"+maxTime+" ; maxWord is :"+maxWord);
}
複製代碼
第二題對應的 分治法 + HashMap
按照前面的案例,咱們首先同樣是要把這十億
個數分紅不少份。例如 1000份
,每份 10萬
。而後使用 HashMap<int,int>
來統計。在每一次的統計中,咱們能夠找出最大的100個數
,爲何只找10萬
中的100個啊?由於咱們有1000份
,其它份裏面的第二大多是這份裏最小的。這樣所有加起來都100*1000個
數了。OK,在咱們找出這100*1000
個侯選數後,繼續分治處理,或者直接進行排序,若是直接排序就是10W個數
。排序算法能夠選快排
等之類的,前100個
就是結果。
位圖法 Bitmap
第一題,略。不是純數字的,不建議採用位圖法
。
第二題:
有了 找出不重複的
的例子作基礎。咱們此時直接知道這題的 正整數
最大也是隻能到 2^23-1
,對於這道題,咱們不須要乘2
,因此咱們申請的內存大小也是512MB
。這樣咱們就能使用這個位圖
把全部數都存進去。若是出現了一次,該bit位 = 1
,沒有就是0。屢次出現的話,咱們就不能累加到bit位
裏面了,由於它最大就是1
。這時候咱們會發現,出現屢次的話,是沒法經過bit位
進行累加記錄的。因此,此題也是不適合採用位圖法
。
例如問:XXXXX中找出最大的一個,最小的一個,最大的幾個,最小的幾個
。這類的就可使用分治法+最小堆/最大堆
秒之。