話說,由於同學認識百度的一個師兄,所以走了內推的流程而沒有進行筆試。下午3點多,列印了份簡曆從學校門口打了個的就真奔百度所在的普天大廈。提前4點前到達,在前台那裡等了一會。一哥門過來把我領了過去,在中廳打了個地方,好了,面試開始。
第一個問題:一個有環的單鏈表,如何找到進入環的地方。當時一聽到環我就差點暈過去,心裡說:我去,這次玩完了。我在那哥門的誘導下,左想右想啊,最後沒有整出來,那哥門最後鬱悶了,說:咱們先問點別的吧。
第二個問題:一個私網主機,一個公網主機,如何讓私網主機通過公網主機進行通訊。這個easy,畢竟平時做網路的,我就給他舉SNAT和DNAT來解決,他說可以。
第三個問題:他自己編的,說一個私人網路A,幾台主機ai,另一個私人網路B幾台主機bi,ai之間是互聯的,bi之間也是互聯的,bi中只有一台主機bn(n!=1),可以連外網,ai中只有一a1與b1之間有物理串連,問A中的主機如何連到外網。聽完這個我又想暈,問了比較白的問題,這些主機有路由功能嗎?那哥門說:沒有。好吧,最後我說可以用隧道。他說,算是種方法,這道題也算是過了。
最後那哥門開始給我介紹,他們部門的工作內容,問我有什麼意向,我知道他覺得我的項目經驗與他們部門是不match的,想讓我轉投其他部門,最後說,一周后等二面的通知。
我的一面就這樣失敗了。
總體來說我的演算法太弱了,雖然暑假裡看了演算法導論,但是過目就忘的那種。下面帖一下第一個問題的解達吧,以祭我一面之靈。
1、如何判斷一個鏈表是不是這類鏈表?
2、如果鏈表為存在環,如果找到環的進入點?
解答:
一、判斷鏈表是否存在環,辦法為:
設定兩個指標(fast, slow),初始值都指向頭,slow每次前進一步,fast每次前進二步,如果鏈表存在環,則fast必定先進入環,而slow後進入環,兩個指標必定相遇。(當然,fast先行頭到尾部為NULL,則為無環鏈表)程式如下:
bool IsExitsLoop(slist *head)
{
slist *slow = head, *fast = head;
while ( fast && fast->next )
{
slow = slow->next;
fast = fast->next->next;
if ( slow == fast ) break;
}
return !(fast == NULL || fast->next == NULL);
}
二、找到環的進入點
當fast若與slow相遇時,slow肯定沒有走遍曆完鏈表,見注釋(1)而fast已經在環內迴圈了n圈(1<=n)。假設slow走了s步,則fast走了2s步(fast步數還等於s 加上在環上多轉的n圈),設環長為r,則:
2s = s + nr
s= nr
設整個鏈表長L,入口環與相遇點距離為x,起點到環進入點的距離為a。
a + x = nr
a + x = (n – 1)r +r = (n-1)r + L - a
a = (n-1)r + (L – a – x)
(L – a – x)為相遇點到環進入點的距離,由此可知,從鏈表頭到環進入點等於(n-1)迴圈內環+相遇點到環進入點,於是我們從鏈表頭、與相遇點分別設一個指標,每次各走一步,兩個指標必定相遇,且相遇第一點為環進入點。程式描述如下:
slist* FindLoopPort(slist *head)
{
slist *slow = head, *fast = head;
while ( fast && fast->next )
{
slow = slow->next;
fast = fast->next->next;
if ( slow == fast ) break;
}
if (fast == NULL || fast->next == NULL)
return NULL;
slow = head;
while (slow != fast)
{
slow = slow->next;
fast = fast->next;
}
return slow;
}
擴充問題:
判斷兩個單鏈表是否相交,如果相交,給出相交的第一個點(兩個鏈表都不存在環)。
比較好的方法有兩個:
一、將其中一個鏈表首尾相連,檢測另外一個鏈表是否存在環,如果存在,則兩個鏈表相交,而檢測出來的依賴環入口即為相交的第一個點。
二、如果兩個鏈表相交,那個兩個鏈表從相交點到鏈表結束都是相同的節點,我們可以先遍曆一個鏈表,直到尾部,再遍曆另外一個鏈表,如果也可以走到同樣的結尾點,則兩個鏈表相交。
這時我們記下兩個鏈表length,再遍曆一次,長鏈表節點先出發前進(lengthMax-lengthMin)步,之後兩個鏈表同時前進,每次一步,相遇的第一點即為兩個鏈表相交的第一個點。
注釋1
設r為環長,則fast指標r/2內可以跑完一圈,若r為奇數,剛r步
內fast會遍曆迴圈內所有點.剛r內一定會跟slow相遇.若r為偶數,r/2步內可令fast跟slow的最近距離為2或1(f追趕s).若為2,則
fast+2=slow
所以下一步時slow的位置是slow+1;而fast則為fast+2;
再下步slow+2,fast+4;
因為之前fast+2=slow,所以
slow-2+4=slow+2
又因為最近距離為1時,只要兩指標各走一步便相遇.
所以兩指標相遇.最大步數為s<=r/2+2(r>=4)