原文地址:http://blog.csdn.net/hackbuteer1/article/details/7348968面試
一、實現一個函數,對一個正整數n,算獲得1須要的最少操做次數。操做規則爲:若是n爲偶數,將其除以2;若是n爲奇數,能夠加1或減1;一直處理下去。算法
例子:
func(7) = 4,能夠證實最少須要4次運算
n = 7
n-1 6
n/2 3
n-1 2
n/2 1
要求:實現函數(實現儘量高效) int func(unsign int n);n爲輸入,返回最小的運算次數。給出思路(文字描述),完成代碼,並分析你算法的時間複雜度。
答:數組
假設n表示成二進制有x bit,能夠看出計算複雜度爲O(2^x),也就是O(n)。
將n轉換到二進制空間來看(好比7爲111,6爲110):
- 若是最後一位是0,則對應於偶數,直接進行除2操做。
- 若是最後一位是1,狀況則有些複雜。
**若是最後幾位是???01,則有可能爲???001,???1111101。在第一種狀況下,顯然應該-1;在第二種狀況下-1和+1最終須要的步數相同。因此在???01的狀況下,應該選擇-1操做。
**若是最後幾位是???011,則有可能爲???0011,???11111011。在第一種狀況下,+1和-1最終須要的步數相同;在第二種狀況下+1步數更少些。因此在???011的狀況下,應該選擇+1操做。
**若是最後有更多的連續1,也應該選擇+1操做。瀏覽器
若是最後剩下的各位都是1,則有11時應該選擇-1;111時+1和-1相同;1111時應選擇+1;大於四個1時也應該選擇+1;緩存
由以上的分析可知,奇數的時候加1或減1,徹底取決於二進制的後兩位,若是後兩位是十、00那麼確定是偶數,選擇除以2,若是後兩位是0一、11,那麼選擇結果會不同的,若是是*****01,那麼選擇減1,若是是*****11,那麼選擇加1,特殊狀況是就是n是3的時候,選擇減1操做。
非遞歸代碼以下:安全
另一種寫法以下:服務器
二、找到知足條件的數組
給定函數d(n)=n+n的各位之和,n爲正整數,如d(78)=78+7+8=93。這樣這個函數能夠當作一個生成器,如93能夠當作由78生成。
定義數A:數A找不到一個數B能夠由d(B)=A,即A不能由其餘數生成。如今要寫程序,找出1至10000裏的全部符合數A定義的數。
回答:
申請一個長度爲10000的bool數組,每一個元素表明對應的值是否能夠有其它數生成。開始時將數組中的值都初始化爲false。
因爲大於10000的數的生成數一定大於10000,因此咱們只需遍歷1到10000中的數,計算生成數,並將bool數組中對應的值設置爲true,表示這個數能夠有其它數生成。
最後bool數組中值爲false的位置對應的整數就是不能由其它數生成的。
三、一個大的含有50M個URL的記錄,一個小的含有500個URL的記錄,找出兩個記錄裏相同的URL。數據結構
回答:
首先使用包含500個url的文件建立一個hash_set。
而後遍歷50M的url記錄,若是url在hash_set中,則輸出此url並從hash_set中刪除這個url。
全部輸出的url就是兩個記錄裏相同的url。
四、海量日誌數據,提取出某日訪問百度次數最多的那個IP。
回答:
若是日誌文件足夠的大,大到不能徹底加載到內存中的話。
那麼能夠考慮分而治之的策略,按照IP地址的hash(IP)%1024值,將海量日誌存儲到1024個小文件中。每一個小文件最多包含4M個IP地址。
對於每一個小文件,能夠構建一個IP做爲key,出現次數做爲value的hash_map,並記錄當前出現次數最多的1個IP地址。
有了1024個小文件中的出現次數最多的IP,咱們就能夠輕鬆獲得整體上出現次數最多的IP。
五、有10個文件,每一個文件1G,每一個文件的每一行都存放的是用戶的query,每一個文件的query均可能重複。如何按照query的頻度排序?
回答:
1)讀取10個文件,按照hash(query)%10的結果將query寫到對應的文件中。這樣咱們就有了10個大小約爲1G的文件。任意一個query只會出如今某個文件中。
2)對於1)中得到的10個文件,分別進行以下操做
-利用hash_map(query,query_count)來統計每一個query出現的次數。
-利用堆排序算法對query按照出現次數進行排序。
-將排序好的query輸出的文件中。
這樣咱們就得到了10個文件,每一個文件中都是按頻率排序好的query。
3)對2)中得到的10個文件進行歸併排序,並將最終結果輸出到文件中。函數
六、螞蟻爬杆問題
有一根27釐米長的細木杆,在第3釐米,7釐米,11釐米,17釐米,23釐米這五個位置上各有一隻螞蟻,木杆很細,不能同時經過兩隻螞蟻,開始時,螞蟻的頭朝向左仍是右是任意的,他們只會朝前走或掉頭,但不會後退,當兩隻螞蟻相遇後,螞蟻會同時掉頭朝反方向走,假設螞蟻們每秒鐘能夠走1釐米的距離。求全部螞蟻都離開木杆的最小時間和最大時間。
答案:
兩隻螞蟻相遇後,各自掉頭朝相反方向走。若是咱們不考慮每一個螞蟻的具體身份,這和兩隻螞蟻相遇後,打個招呼繼續向前走沒有什麼區別。
全部螞蟻都離開木杆的最小時間爲
max(min(3,27-3),min(7,27-7), min(11,27-11), min(17,27-17),min(23,27-23))=11
全部螞蟻都離開木杆的最大時間爲
max(max(3,27-3),max(7,27-7), max(11,27-11), max(17,27-17),max(23,27-23))=24url
七、當在瀏覽器中輸入一個url後回車,後臺發生了什麼?好比輸入url後,你看到了百度的首頁,那麼這一切是如何發生的呢?
回答:
簡單來講有如下步驟:
一、查找域名對應的IP地址。這一步會依次查找瀏覽器緩存,系統緩存,路由器緩存,ISPDNS緩存,根域名服務器。
二、向IP對應的服務器發送請求。
三、服務器響應請求,發回網頁內容。
四、瀏覽器解析網頁內容。
固然,因爲網頁可能有重定向,或者嵌入了圖片,AJAX,其它子網頁等等,這4個步驟可能反覆進行屢次才能將最終頁面展現給用戶。
八、判斷兩棵樹是否相等,請實現兩棵樹是否相等的比較,相等返回1,不然返回其餘值,並說明算法複雜度。
數據結構爲:
函數接口爲:int CompTree(TreeNode* tree1,TreeNode* tree2);
注:A、B兩棵樹相等當且僅當RootA->c==RootB-->c,並且A和B的左右子樹相等或者左右互換相等。
遞歸方法:
時間複雜度:
在樹的第0層,有1個節點,咱們會進行1次函數調用;
在樹的第1層,有2個節點,咱們可能會進行4次函數調用;
在樹的第2層,有4個節點,咱們可能會進行16次函數調用;
....
在樹的第x層,有2^x個節點,咱們可能會進行(2^x)^2次函數調用;
因此假設總節點數爲n,則算法的複雜度爲O(n^2)。
騰訊面試題:求一個論壇的在線人數,假設有一個論壇,其註冊ID有兩億個,每一個ID從登錄到退出會向一個日誌文件中記下登錄時間和退出時間,要求寫一個算法統計一天中論壇的用戶在線分佈,取樣粒度爲秒。
回答:
一天總共有3600*24=86400秒。
定義一個長度爲86400的整數數組intdelta[86400],每一個整數對應這一秒的人數變化值,可能爲正也可能爲負。開始時將數組元素都初始化爲0。
而後依次讀入每一個用戶的登陸時間和退出時間,將與登陸時間對應的整數值加1,將與退出時間對應的整數值減1。
這樣處理一遍後數組中存儲了每秒中的人數變化狀況。
定義另一個長度爲86400的整數數組intonline_num[86400],每一個整數對應這一秒的論壇在線人數。
假設一天開始時論壇在線人數爲0,則第1秒的人數online_num[0]=delta[0]。第n+1秒的人數online_num[n]=online_num[n-1]+delta[n]。
這樣咱們就得到了一天中任意時間的在線人數。
九、三個警察和三個囚徒的過河問題
三個警察和三個囚徒共同旅行。一條河擋住了去路,河邊有一條船,可是每次只能載2人。存在以下的危險:不管在河的哪邊,當囚徒人數多於警察的人數時,將有警察被囚徒殺死。問題:請問如何肯定渡河方案,才能保證6人安全無損的過河。
答案:第一次:兩囚徒同過,回一囚徒
第二次:兩囚徒同過,回一囚徒
第三次:兩警察同過,回一囚徒一警察(此時對岸還剩下一囚徒一警察,是安全狀態)
第四次:兩警察同過,回一囚徒(此時對岸有3個警察,是安全狀態)
第五次:兩囚徒同過,回一囚徒
第六次:兩囚徒同過;over
十、從300萬字符串中找到最熱門的10條
搜索的輸入信息是一個字符串,統計300萬輸入信息中的最熱門的前10條,咱們每次輸入的一個字符串爲不超過255byte,內存使用只有1G。請描述思想,寫出算法(c語言),空間和時間複雜度。
答案:
300萬個字符串最多(假設沒有重複,都是最大長度)佔用內存3M*1K/4=0.75G。因此能夠將全部字符串都存放在內存中進行處理。
可使用key爲字符串(事實上是字符串的hash值),值爲字符串出現次數的hash來統計每一個每一個字符串出現的次數。並用一個長度爲10的數組/鏈表來存儲目前出現次數最多的10個字符串。
這樣空間和時間的複雜度都是O(n)。
十一、如何找出字典中的兄弟單詞。給定一個單詞a,若是經過交換單詞中字母的順序能夠獲得另外的單詞b,那麼定義b是a的兄弟單詞。如今給定一個字典,用戶輸入一個單詞,如何根據字典找出這個單詞有多少個兄弟單詞?
答案:
使用hash_map和鏈表。
首先定義一個key,使得兄弟單詞有相同的key,不是兄弟的單詞有不一樣的key。例如,將單詞按字母從小到大從新排序後做爲其key,好比bad的key爲abd,good的key爲dgoo。
使用鏈表將全部兄弟單詞串在一塊兒,hash_map的key爲單詞的key,value爲鏈表的起始地址。
開始時,先遍歷字典,將每一個單詞都按照key加入到對應的鏈表當中。當須要找兄弟單詞時,只需求取這個單詞的key,而後到hash_map中找到對應的鏈表便可。
這樣建立hash_map時時間複雜度爲O(n),查找兄弟單詞時時間複雜度是O(1)。
十二、找出數組中出現次數超過一半的數,如今有一個數組,已知一個數出現的次數超過了一半,請用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三、找出被修改過的數字
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。
1四、設計DNS服務器中cache的數據結構。
要求設計一個DNS的Cache結構,要求可以知足每秒5000以上的查詢,知足IP數據的快速插入,查詢的速度要快。(題目還給出了一系列的數據,好比:站點數總共爲5000萬,IP地址有1000萬,等等)
回答:
DNS服務器實現域名到IP地址的轉換。
每一個域名的平均長度爲25個字節(估計值),每一個IP爲4個字節,因此Cache的每一個條目須要大概30個字節。
總共50M個條目,因此須要1.5G個字節的空間。能夠放置在內存中。(考慮到每秒5000次操做的限制,也只能放在內存中。)
能夠考慮的數據結構包括hash_map,字典樹,紅黑樹等等。
1五、找出給定字符串對應的序號。
序列Seq=[a,b,…z,aa,ab…az,ba,bb,…bz,…,za,zb,…zz,aaa,…]相似與excel的排列,任意給出一個字符串s=[a-z]+(由a-z字符組成的任意長度字符串),請問s是序列Seq的第幾個。
回答:
注意到每滿26個就會向前進一位,相似一個26進制的問題。
好比ab,則位置爲26*1+2;
好比za,則位置爲26*26+1;
好比abc,則位置爲26*26*1+26*2+3;
1六、找出第k大的數字所在的位置。寫一段程序,找出數組中第k大小的數,輸出數所在的位置。例如{2,4,3,4,7}中,第一大的數是7,位置在4。第二大、第三大的數都是4,位置在一、3隨便輸出哪個都可。
答案:
先找到第k大的數字,而後再遍歷一遍數組找到它的位置。因此題目的難點在於如何最高效的找到第k大的數。
咱們能夠經過快速排序,堆排序等高效的排序算法對數組進行排序,而後找到第k大的數字。這樣整體複雜度爲O(NlogN)。
咱們還能夠經過二分的思想,找到第k大的數字,而沒必要對整個數組排序。從數組中隨機選一個數t,經過讓這個數和其它數比較,咱們能夠將整個數組分紅了兩部分而且知足,{x,xx,...,t}<{y,yy,...}。
在將數組分紅兩個數組的過程當中,咱們還能夠記錄每一個子數組的大小。這樣咱們就能夠肯定第k大的數字在哪一個子數組中。
而後咱們繼續對包含第k大數字的子數組進行一樣的劃分,直到找到第k大的數字爲止。
平均來講,因爲每次劃分都會使子數組縮小到原來1/2,因此整個過程的複雜度爲O(N)。
1七、給40億個不重複的unsigned int的整數,沒排過序的,而後再給幾個數,如何快速判斷這幾個數是否在那40億個數當中?
答案:
unsigned int的取值範圍是0到2^32-1。咱們能夠申請連續的2^32/8=512M的內存,用每個bit對應一個unsigned int數字。首先將512M內存都初始化爲0,而後每處理一個數字就將其對應的bit設置爲1。當須要查詢時,直接找到對應bit,看其值是0仍是1便可。
1八、在一個文件中有10G個整數,亂序排列,要求找出中位數。內存限制爲2G。
回答:
不妨假設10G個整數是64bit的。
2G內存能夠存放256M個64bit整數。
咱們能夠將64bit的整數空間平均分紅256M個取值範圍,用2G的內存對每一個取值範圍內出現整數個數進行統計。這樣遍歷一邊10G整數後,咱們便知道中數在那個範圍內出現,以及這個範圍內總共出現了多少個整數。
若是中數所在範圍出現的整數比較少,咱們就能夠對這個範圍內的整數進行排序,找到中數。若是這個範圍內出現的整數比較多,咱們還能夠採用一樣的方法將此範圍再次分紅多個更小的範圍(256M=2^28,因此最多須要3次就能夠將此範圍縮小到1,也就找到了中數)。
1九、時分秒針在一天之類重合多少次?(24小時)
2次
而時針和分針重合了22次。
20、將多個集合合併成沒有交集的集合。 給定一個字符串的集合,格式如:{aaabbbccc},{bbbddd},{eeefff},{ggg},{dddhhh}要求將其中交集不爲空的集合合併,要求合併完成後的集合之間無交集,例如上例應輸出{aaabbbcccdddhhh},{eeefff},{ggg}。 (1)請描述你解決這個問題的思路; (2)請給出主要的處理流程,算法,以及算法的複雜度 (3)請描述可能的改進。回答: 集合使用hash_set來表示,這樣合併時間複雜度比較低。 一、給每一個集合編號爲0,1,2,3... 二、建立一個hash_map,key爲字符串,value爲一個鏈表,鏈表節點爲字符串所在集合的編號。遍歷全部的集合,將字符串和對應的集合編號插入到hash_map中去。 三、建立一個長度等於集合個數的int數組,表示集合間的合併關係。例如,下標爲5的元素值爲3,表示將下標爲5的集合合併到下標爲3的集合中去。開始時將全部值都初始化爲-1,表示集合間沒有互相合並。在集合合併的過程當中,咱們將全部的字符串都合併到編號較小的集合中去。 遍歷第二步中生成的hash_map,對於每一個value中的鏈表,首先找到最小的集合編號(有些集合已經被合併過,須要順着合併關係數組找到合併後的集合編號),而後將鏈表中全部編號的集合都合併到編號最小的集合中(經過更改合併關係數組)。 四、如今合併關係數組中值爲-1的集合即爲最終的集合,它的元素來源於全部直接或間接指向它的集合。 算法的複雜度爲O(n),其中n爲全部集合中的元素個數。 題目中的例子: 0:{aaabbbccc} 1:{bbbddd} 2:{eeefff} 3:{ggg} 4:{dddhhh} 生成的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個集合合併到了一塊兒, 2一、平面內有11個點,由它們連成48條不一樣的直,由這些點可連成多少個三角形?解析:首先你要分析,平面中有11個點,若是這些點中任意三點都沒有共線的,那麼一共應該有C(11,2)=55, 但是,題目中說能夠鏈接成48條直線,那麼這11個點中一定有多點共線的狀況。 55-48=7,從7來分析:假設有一組三個點共線,那麼能夠組成的直線在55的基礎上應該減去C(3,2)-1=2 2*3=6≠7,所以,能夠判定不只有三點共線的,也可能有四個點共線的可能。假設有一組四個點共線,那麼能夠組成的直線在55的基礎上應該減去C(4,2)-1=5 (備註,五個點共線的可能不存在,由於,C(5,2)-1=9>7,故不可能有五條直線共線。)所以,三點共線少2條,4點共線少5條,只有一個4點共線,一個3點共線才能知足條件,其他狀況不能知足少了7條直線。那麼,這11個點能組成的三角形的個數爲,C(11,3)-C(3,3)-C(4,3)=165-1-4=160 (備註,三個點共線不能組成三角形)