1. 程式人生 > >九章算法-面試題總結(算法、強化算法、系統設計高清視頻觀看)

九章算法-面試題總結(算法、強化算法、系統設計高清視頻觀看)

1 落單的數

題目描述:

有2n+1個數,其中2n個數兩兩成對,1個數落單,找出這個數。要求O(n)的時間復雜度,O(1)的空間復雜度。

進階問題:如果有2n+2個數,其中有2個數落單,該怎麽辦?

分析

初階:將2n+1個數異或起來,相同的數會抵消,異或的答案就是要找的數。

進階:假設兩個不同的數是a和b,並且a!=b,將2n+2個數異或起來就會得到c=a xor b,並且c不等於0。因此在c的二進制位中找到一個為1的位,可推斷在這位上a和b分別為0和1,因此將2n+2個數分為該位位0的組和該位為1的組,兩組中各自會包含2n’+1個數和2n’’+1個數,用初階的算法即可解決。

2 抄書問題

題目描述:

有n本書和k個抄寫員。要求n本書必須連續的分配給這k個抄寫員抄寫。也就是說前a1本書分給第一個抄寫員,接下來a2本書分給第二個抄寫員,如此類推(a1,a2需要你的算法來決定)。給定n,k和每本書的頁數p1,p2..pn,假定每個抄寫員速度一樣(每分鐘1頁),k個抄寫員同時開始抄寫,問最少需要多少時間能夠將所有書全部抄寫完工?(提示:本題有很多種算法可以在不同的時間復雜度下解決,需要盡可能的想到所有的方法)

分析

解法1:動態規劃 設f[i][j]代表前i本書分給j個抄寫員抄完的最少耗時。答案就是f[n][k]。狀態轉移方程f[i][j] = min{max(f[x][j-1], sum(x+1, i)), j<x<i}。其中x是在枚舉第j個抄寫員是從哪本書開始抄寫。 時間復雜度O(n^2*k)

解法2:動態規劃+決策單調。 同上一解法,但在x的枚舉上進行優化,設s[i][j]為使得f[i][j]獲得最優值的x是多少。根據四邊形不等式原理,有s[i][j-1]>=s[i][j]>=s[i-1][j]。因此x這一層的枚舉不再是每次都是n而是總共加起來n。 時間復雜度O(n*k)

解法3:二分答案。二分最慢的時間,然後嘗試一本本的加進來,加滿了就給一個抄寫員。看最後需要的抄寫員數目是多余k個還是少於k個,然後來決定是將答案往上調整還是往下調整。 時間復雜度O( n log SUM(pi) )

3 找壞球

題目描述:

有12個球,1個沒有砝碼的天秤。其中有11個球的重量是一樣的,另外1個是壞球,和其他球的重量不一樣,但無法確定是輕了還是重了。請問如何用天秤稱3次,就找到壞球並確定是輕了還是重了。(沒有砝碼的天秤只能比較出兩邊誰重誰輕或是重量相等,無法求得具體的重量差)

分析

12個球,編號A=(1,2,3,4 )B=(5,6,7,8)C=(9,10,11,12)

分為三組:A, B, C。

  • 先比較A,B,如果A與B平衡,則A,B中均為好球

    • 比較5,6,7與9,10,11
      • 若平衡,則壞球為8或12
        • 比較8與任何一個好球,平衡,壞球為12;不平,壞球為8。
      • 若不平,則目前可以知道是壞的球比好球是重還是輕,假設為重
        • 比較9,10,若平衡,則壞球為12;不平,壞球為重的那個
  • 若A,B不平,則C為好球

    • 比較1,2,5 與 3,4,6(交叉,這玩意面試的時候能想到?)
      • 若平衡,則壞球在7,8之間,且之前已經得知輕重的一個關系,再比較一次7,8
      • 若不平衡,或者1,2為壞球,或者5,6為壞球,再比較一次。

4 索引比例

題目描述:

估算Baidu和Google的網頁索引數量之比

分析

我們可以假設能夠通過搜索引擎做到如下的兩件事:

  1. 隨機取到一個網頁

  2. 判斷某個網頁(url)是否被索引

因此,在Baidu上多次隨機關鍵詞進行搜索,獲取到每個關鍵詞對應結果的若幹網頁信息(url),將這些url在Google上查找是否被索引到。從而得到Baidu網頁中Google索引的的比例為1/B。

對Google做同樣的事情,得到Google網頁中被Baidu索引的比例1/G。由此可知Baidu和Google的索引比例為B:G

5 第k大的數

題目描述

初階:有兩個數組A和B,假設A和B已經有序(從大到小),求A和B數組中所有數的第K大。

進階:有N臺機器,每臺機器上有一個有序大數組,需要求得所有機器上所有數中的第K大。註意,需要考慮N臺機器的並行計算能力。

分析

初階:比較A[k/2]和B[k/2],如果A[k/2]>=B[k/2]那麽A的前k/2個數一定都在前k-1大中,將A數組前k/2個數扔掉,反之扔掉B的前k/2個數。將k減小k/2。重復上述操作直到k=1。比較A和B的第一個數即可得到結果。時間復雜度O(logk) Leetcode原題,據說極其高頻

進階:二分答案S,將S廣播給每臺機器,每臺機器用二分法求得有多少比該數小的數。匯總結果後可判斷是該將S往上還是往下調整。

面試官角度:

初階問題是一個比較難度大的算法題。需要有一定的算法訓練功底。主要用到的思想是遞歸。首先容易想到的方法是合並兩個數組(見面試題5,有序數組的合並),這樣復雜度為O(k),那麽答出這個以後,面試官會問你,還有更好的方法麽?這個時候就要往O(logk)的思路去想,O(logk)就意味著需要用一種方法每次將k的規模減小一半,於是想到,每次要扔掉一個數組或兩個數組中的k/2個數,於是想到去比較A[k/2]和B[k/2],仔細思考比較結果,然後想到較大的那一方的前k/2個數一定都在前k-1大的數中,於是可以扔掉。

進階問題的考察點是逆向思維。二分答案是一種常見的算法思路(見面試題2 抄書問題),所以當你想不出題目的時候,往往可以試試看是否可以二分答案。因為需要發揮N臺機器的並行計算能力,所以想到讓每臺機器互不相關的做一件事情,然後將結果匯總來判斷。

進階題偽代碼

int FindK(vector<vector<int> > & mq, int N, int k) { int ans_upper = INT_MAX; int ans_lower = INT_MIN; int sum_len = 0; while(sum_len != k) { ans = ans_lower + (ans_upper - ans_lower) /2; for (int i=0; i<N; i++) { sum_len += left_count_binarySearch(mq[i], ans); } if (sum_len > k) ans_upper = ans; if (sum_len < k) ans_lower = ans; } return ans; } 

6 前k大的和,這題很有意思

題目描述

初階:有兩個數組A和B,每個數組有k個數,從兩個數組中各取一個數加起來可以組成k*k個和,求這些和中的前k大。

進階:有N個數組,每個數組有k個數,從N個數組中各取一個數加起來可以組成k^n個和,求這些和中的前k大。

分析

~ 9 7
11 20 18
7 16 14
1 10 8
0 9 7

可以這個問題轉化為N個有序數組的合並問題,每個數組為:

A[0]+B[0]<=A[0]+B[1]<=A[0]+B[2]<=A[0]+B[3]...<=A[0]+B[N?1]A[0]+B[0]<=A[0]+B[1]<=A[0]+B[2]<=A[0]+B[3]...<=A[0]+B[N?1] A[1]+B[0]<=A[1]+B[1]<=A[1]+B[2]<=A[1]+B[3]...<=A[1]+B[N?1]A[1]+B[0]<=A[1]+B[1]<=A[1]+B[2]<=A[1]+B[3]...<=A[1]+B[N?1] A[2]+B[0]<=A[2]+B[1]<=A[2]+B[2]<=A[2]+B[3]...<=A[2]+B[N?1]A[2]+B[0]<=A[2]+B[1]<=A[2]+B[2]<=A[2]+B[3]...<=A[2]+B[N?1] ............ A[N?1]+B[0]<=A[N?1]+B[1]<=A[N?1]+B[2]<=A[N?1]+B[3]...<=A[N?1]+B[N?1]A[N?1]+B[0]<=A[N?1]+B[1]<=A[N?1]+B[2]<=A[N?1]+B[3]...<=A[N?1]+B[N?1]

因此,維護一個包含N個元素的最大堆,然後每取一個元素T,T所在列的下一個元素入堆,這樣循環取K個數,即完成了求TopK的問題。

進階:

先求1,2前K大,然後再與下一個求前K大。

7 賽馬問題

題目描述

有25匹馬,有一個5個賽道的馬場,每場比賽可以決出5匹馬的排名,假設每匹馬發揮穩定,且不會出現名次相同的情況。問,如果要知道25匹馬中跑得最快的馬,需要幾場比賽?如果需要知道跑得第二快的馬,需要幾場比賽?第三快的呢?

分析

  1. 最快的,需要6次。

    • 每五匹賽一次(5次),每次的第一名,再一起賽一次(1次)
  2. 第二快的,需要7次。

    • 每五匹賽一次(5次),每次的第一名,再一起賽一次(1次)
    • 最快的那組的第二名,與上次的第二名,跑一次。(1次)
  3. 第三快的,需要7次。

    • 每五匹賽一次(5次),每次的第一名,再一起賽一次(1次)
    • 最快的那組的第二、三名,與上次的第二名那組裏的第二名,與上次的第二、第三名一起跑一次。

8 最大子區間/矩陣

題目描述

初階:數組A中有N個數,需要找到A的最大子區間,使得區間內的數和最大。即找到0<=i<=j<N,使得A[i]+A[i+1] … + A[j]最大。A中元素有正有負。

進階:矩陣A中有N*N個數,需要找到A的最大的子矩陣。

分析

第一個是經典的連續子序列問題,DP或者轉化為前綴和數組進行貪心。

第二個,枚舉上下行,中間壓縮為一個值,再采用第一個問題中的方法求解,復雜度O(n^3)

9 從輸入流中隨機取記錄

題目描述

有一個很大很大的輸入流,大到沒有存儲器可以將其存儲下來,而且只輸入一次,如何從這個輸入流中等概率隨機取得m個記錄。

分析

維護一個內存空間,存放前m個記錄,然後遇到第k元素,從m個記錄中,隨機抽取一個元素,然後以m/k的概率替換這個元素。

簡單證明

假設數據流一共N個元素,設第k個元素最後存在於所選取的記錄裏,則當遇到第k個元素時,k一定被替換,而k+1到最後N一定不被替換。

第k個元素不管替換了之前的哪一個元素,那肯定會留下來,因此概率為m/k。而後面第j個元素會替換k的概率是,j要替換,且隨機從m個元素中選到了k。其概率為mj?1mmj?1m

因此,第k個元素,最終仍會存在的概率為:

p=mk?(1?mk+1?1m)?(1?mk+2?1m)?(1?mk+3?1m)...(1?mN?1m)=mNp=mk?(1?mk+1?1m)?(1?mk+2?1m)?(1?mk+3?1m)...(1?mN?1m)=mN

因此每個元素被取得的概率相等。

10 最常訪問IP

題目描述

給你一個海量的日誌數據,提取出某日訪問網站次數最多的IP地址。

分析

將日誌文件劃分成適度大小的M份存放到處理節點。

每個map節點所完成的工作:統計訪問百度的ip的出現頻度(比較像統計詞頻,使用字典樹),並完成相同ip的合並(combine)。

map節點將其計算的中間結果partition到R個區域,並告知master存儲位置,所有map節點工作完成之後,reduce節點首先讀入數據,然後以中間結果的key排序,對於相同key的中間結果調用用戶的reduce函數,輸出。

掃描reduce節點輸出的R個文件一遍,可獲得訪問網站度次數最多的ip。

面試官角度:

該問題是經典的Map-Reduce問題。一般除了問最常訪問,還可能會問最常訪問的K個IP。一般來說,遇到這個問題要先回答Map-Reduce的解法。因為這是最常見的解法也是一般面試官的考點。如果面試官水平高一點,要進一步問你有沒有其他解法的話,該問題有很多概率算法。能夠在極少的空間復雜度內,掃描一遍log即可得到Top k Frequent Items(在一定的概率內)。有興趣的讀者,可以搜搜“Sticky Sampling”,”Lossy Counting”這兩個算法。

九章算法-面試題總結(算法、強化算法、系統設計高清視頻觀看)