百度面試算法題


1.代碼編譯過程

  1. cpp文件中展開include文件。
  2. 將每個cpp文件編譯為一個對應的obj文件。
  3. 連接obj文件成為一個exe文件(或者其它的庫文件)

2.100W個整數中求最小的k個數,有哪些方法,優缺點

快速排序: 分區時,根據數P將數組分為兩部分,設大於P的數個數為a,小於P的數的個數為b。如果,a>=k,則從這a個數取最大的k個數,若a<k,則從b個數取最大的k-a-1個。

 

3.兩個10G的文件中,求含有相同整數,有哪些方法,優缺點

1)快排+二分查找 (2)位圖法

位圖法的應用

1、給40億個不重復的unsigned int的整數,沒排過序的,然后再給一個數,如何快速判斷這個數是否在那40億個數當中   首先,將這40億個數字存儲到bitmap中,然后對於給出的數,判斷是否在bitmap中即可。

2、使用位圖法判斷整形數組是否存在重復       遍歷數組,一個一個放入bitmap,並且檢查其是否在bitmap中出現過,如果沒出現放入,否則即為重復的元素。

3、在2.5億個整數中找出不重復的整數,注,內存不足以容納這2.5億個整數       參 考的一個方法是:采用2-Bitmap(每個數分配2bit00表示不存在,01表示出現一次,10表示多次,11無意義)。其實,這里可以使用兩個普 通的Bitmap,即第一個Bitmap存儲的是整數是否出現,如果再次出現,則在第二個Bitmap中設置即可。這樣的話,就可以使用簡單的1- Bitmap了。

 

hash_map:

其基本原理是:使用一個下標范圍比較大的數組來存儲元素。可以設計一個函數(哈希函數,也叫做散列函數),使得每個元素的關鍵字都與一個函數值(即數組下標,hash值)相對應,於是用這個數組單元來存儲這個元素;也可以簡單的理解為,按照關鍵字為每一個元素分類,然后將這個元素存儲在相應所對應的地方,稱為桶。  但是,不能夠保證每個元素的關鍵字與函數值是一一對應的,因此極有可能出現對於不同的元素,卻計算出了相同的函數值,這樣就產生了沖突,換句話說,就是把不同的元素分在了相同的之中。 總的來說,直接定址解決沖突是哈希表的兩大特點。  hash_map,首先分配一大片內存,形成許多桶。是利用hash函數,對key進行映射到不同區域(桶)進行保存。

其插入過程是:    

1. 得到key    

2. 通過hash函數得到hash    

3. 得到桶號(一般都為hash值對桶數求模  

4. 存放keyvalue在桶內。 

其取值過程是  

1. 得到key    

2. 通過hash函數得到hash    

3. 得到桶號(一般都為hash值對桶數求模  

4. 比較桶的內部元素是否與key相等,若都不相等,則沒有找到。 

5. 取出相等的記錄的value  hash_map中直接地址用hash函數生成,解決沖突,用比較函數解決。這里可以看出,如果每個桶內部只有一個元素,那么查找的時候只有一次比較。當許多桶內沒有值時,許多查詢就會更快了(指查不到的時候).  由此可見,要實現哈希表, 和用戶相關的是:hash函數和比較函數。這兩個參數剛好是我們在使用hash_map時需要指定的參數。

有一個1G大小的一個文件,里面每一行是一個詞,詞的大小不超過16字節,內存限制大小是1M。返回頻數最高的100個詞。

方案1:順序讀文件中,對於每個詞x,取,然后按照該值存到5000個小文件(記為)中。這樣每個文件大概是200k左右。如果其中的有的文件超過了1M大小,還可以按照類似的方法繼續往下分,知道分解得到的小文件的大小都不超過1M。對每個小文件,統計每個文件中出現的詞以及相應的頻率(可以采用trie/hash_map等),並取出出現頻率最大的100個詞(可以用含100個結點的最小堆),並把100詞及相應的頻率存入文件,這樣又得到了5000個文件。下一步就是把這5000個文件進行歸並(類似與歸並排序)的過程了。

海量日志數據,提取出某日訪問百度次數最多的那個IP

方案1:首先是這一天,並且是訪問百度的日志中的IP取出來,逐個寫入到一個大文件中。注意到IP32位的,最多有IP。同樣可以采用映射的方法,比如模1000,把整個大文件映射為1000個小文件,再找出每個小文中出現頻率最大的IP(可以采用hash_map進行頻率統計,然后再找出頻率最大的幾個)及相應的頻率。然后再在這1000個最大的IP中,找出那個頻率最大的IP,即為所求。

4.僵屍進程產生的原因及解決方式:

如果子進程先於父進程退出, 同時父進程又沒有調用wait/waitpid,則該子進程將成為僵屍進程。通過ps命令,我們可以看到該進程的狀態為Z(表示僵死)

一般,為了防止產生僵屍進程,在fork子進程之后我們都要wait它們;同時,當子進程退出的時候,內核都會給父進程一個SIGCHLD信號,所以我們可以建立一個捕獲SIGCHLD信號的信號處理函數,在函數體中調用wait(或waitpid),就可以清理退出的子進程以達到防止僵屍進程的目的。

 

 

 

給你一個長度為N的鏈表。N很大,但你不知道N有多大。你的任務是從這N個元素中隨機取出k個元素。你只能遍歷這個鏈表一次。你的算法必須保證取出的元素恰好有k個,且它們是完全隨機的(出現概率均等)。

解:先選中前k個, 從第k+1個元素到最后一個元素為止, 以k/i (i=k+1, k+2,...,N)的概率選中第i個元素,並且隨機替換掉一個原先選中的元素,這樣遍歷一次得到k個元素, 可以保證完全隨機選取。這個算法叫做蓄水池抽樣

有20個數組,每個數組里面有500個數組,降序排列,每個數字是32位的unit,求出這10000個數字中最大的500個。

將 20 個數組合並為 1 個,挨着連接起來即可,不必保證有序。在合並的數組中隨機選取一個元素,然后將所有小於此元素的元素放在其左側,大於到右側。完成操作后,如果原來被選中的元素剛好處在右數第 500 的位置,那從它開始向右的元素即為所求。否則,如果右端元素數目大於 500,則對右端序列遞歸使用此方法;否則,如果左端序列數目大於 10000-500,則對左端序列遞歸使用此方法。復雜度 expected O(n)

在一個數組中除兩個數字只出現1次外,其它數字都出現了2次, 要求盡快找出這兩個數字。

位操作方法

單鏈表:

找出單鏈表的倒數第4個元素:建立兩個指針,第一個先走4步,然后第2個指針也開始走,兩個指針步伐(前進速度)一致。

從無頭單鏈表中刪除節點:這里采用了“移花接木”的方法。設該節點為B,下一個節點為C。那么,首先將B節點的內容替換為C節點的內容,然后,將C節點刪除

判斷兩個鏈表是否相交並找出交點:先遍歷第一個鏈表到他的尾部,然后將尾部的next指針指向第二個鏈表(尾部指針的next本來指向的是null)。這樣兩個鏈表就合成了一個鏈表,判斷原來的兩個鏈表是否相交也就轉變成了判斷新的鏈表是否有環的問題了

找出帶環鏈表中環的起點:用兩個步長分別為1和2的指針遍歷鏈表,直到兩者相遇,此時慢指針走過的長度就是環的長度。另外相遇后把其中指針重新設定為起始點,讓兩個指針以步長1再走一遍鏈表,相遇點就是環的起始點。

單鏈表反序,並返回新鏈表的頭指針:

1. struct ListNode *reverseList(struct ListNode *head)  

2. {  

3.     struct ListNode *newHead = NULL;  

4.     struct ListNode *tmp = NULL;  

5.     while(head != NULL)  

6.     {  

7.         tmp = head;  

8.         head = head -> next;  

9.         tmp->next = newHead;  

10.         newHead = tmp;  

11.     }  

12.     return newHead;  

13. }

 

棧問題:

如何用一個數組實現兩個棧:分別用數組的兩端作為兩個棧的起點,向中間擴展,兩個棧中的元素總和不超過n時,兩個棧不會相遇。

二叉樹:

找出二叉樹上任意兩個結點的最近共同父結點:首先數一下兩個結點的深度,然后比較深的那個往上走(深-淺)步,最后同時往上走,肯定會命中最近共同父節點的。如果你把二叉樹的所有節點看成N的話,我這個算法只需要lg(N)就可以搞定了

在二叉樹中找出和為某一值的所有路徑:到達一個節點之后計算當前節點和sum的和,如果為target,輸出路徑返回,如果大於target,則直接返回,如果小於,則將當前節點的值入棧,更新sum的值,繼續遍歷,遍歷完成之后,也就是從當前節點返回的時候,將其從棧中彈出,更新sum

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM