鍊錶常見面試題

2021-06-17 18:39:02 字數 3322 閱讀 9988

1、如何判斷乙個單鏈表有環

2、如何判斷乙個環的入口點在**

3、如何知道環的長度

4、如何知道兩個單鏈表(無環)是否相交

5、如果兩個單鏈表(無環)相交,如何知道它們相交的第乙個節點是什麼

6、如何知道兩個單鏈表(有環)是否相交

7、如果兩個單鏈表(有環)相交,如何知道它們相交的第乙個節點是什麼

1、採用快慢步長法。令兩個指標p和q分別指向頭結點,p每次前進一步,q每次前進兩步,如果p和q能重合,則有環。可以這麼理解,這種做法相當於p靜止不動,q每次前進一步,所有肯定有追上p的時候。

我們注意到,指標p和q分別以速度為1和2

前進。如果以其它速度前進是否可以呢?

假設p和q分別以速度為v1和v2前進。如果有環,設指標p和q第一次進入環時,他們相對於環中第乙個節點的偏移位址分別為a和b

(可以把偏移位址理解為節點個數)

這樣,可以看出,鍊錶有環的充要條件就是某一次迴圈時,指標p和q的值相等,就是它們相對環中首節點的偏移量相等。

我們設環中的結點個數為n,程式迴圈了m次。

由此可以有下面等式成立:(mod(n)即對n取餘

)(a+m*v1)mod(n) = (b+m*v2) mod(n)

設等式左邊mod(n)的最大整數為k1,等式右邊mod(n)的最大整數為k2,則

(a+m*v1)-k1*n = (b+m*v2)-k2*n

整理以上等式:

m= |((k2-k1)*n+a-b)/( v2-v1)|       ①

如果是等式①成立,就要使迴圈次數m為一整數。顯然如果v2-v1為1

,則等式成立。

這樣p和q分別以速度為v1和v2且|v2-v1|為1時,按以上演算法就可找出鍊錶中是否有環。當然|v2-v1|不為1時,也可能可以得出符合條件的m。

[cpp]

view plain

copy

bool

i***itsloop(slist *head)  

return

!(fast == null || fast->next == null);  

}  

時間複雜度分析:假設甩尾(在環外)長度為 len1(結點個數),環內長度為 len2,鍊錶總長度為n,則n=len1+len2

。當p步長為1,q步長為2時,p指標到達環入口需要len1時間,p到達入口後,q處於**不確定,但是肯定在環內,此時p和q開始追趕,q最長需要len2時間就能追上p(p和q都指向環入口),最短需要1步就能追上p(p指向環入口,q指向環入口的前乙個節點)。事實上,每經過一步,q和p的距離就拉近一步,因此,經過q和p的距離步就可以追上p。因此總時間複雜度為o(n),n為鍊錶的總長度。

2、分別從煉表頭和碰撞點,同步地一步一步前進掃瞄,直到碰撞,此碰撞點即是環的入口。

證明如下:

鍊錶形狀類似數字 6 。 

假設甩尾(在環外)長度為 a(結點個數),環內長度為 b 。 

則總長度(也是總結點數)為 a+b 。 

從頭開始,0 base 編號。

將第 i 步訪問的結點用 s(i) 表示。i = 0, 1 ... 

當 i<a 時,s(i)=i ; 

當 i≥a 時,s(i)=a+(i-a)%b 。

分析追趕過程。 

兩個指標分別前進,假定經過 x 步後,碰撞。則有:s(x)=s(2x) 

由環的週期性有:2x=tb+x 。得到 x=tb 。 

另,碰撞時,必須在環內,不可能在甩尾段,有 x>=a 。

連線點為從起點走 a 步,即 s(a)。 

s(a) = s(tb+a) = s(x+a)。 

得到結論:從碰撞點 x 前進 a 步即為連線點。

根據假設易知 s(a-1) 在甩尾段,s(a) 在環上,而 s(x+a) 必然在環上。所以可以發生碰撞。 

而,同為前進 a 步,同為連線點,所以必然發生碰撞。

綜上,從 x 點和從起點同步前進,第乙個碰撞點就是連線點。

[cpp]

view plain

copy

slist* findloopport(slist *head)  

if(fast == null || fast->next == null)  

return

null;  

slow = head;  

while

(slow != fast)  

return

slow;  

}  

時間複雜度分析:假設甩尾(在環外)長度為 len1(結點個數),環內長度為 len2 。則時間複雜度為「環是否存在的時間複雜度」+o(len1)

3、從碰撞點開始,兩個指標p和q,q以一步步長前進,q以兩步步長前進,到下次碰撞所經過的操作次數即是環的長度。這很好理解,比如兩個運動員a和b從起點開始跑步,a的速度是b的兩倍,當a跑玩一圈的時候,b剛好跑完兩圈,a和b又同時在起點上。此時a跑的長度即相當於環的長度。

假設甩尾(在環外)長度為 len1(結點個數),環內長度為 len2 ,則時間複雜度為「環是否存在的時間複雜度」+o(len2)。

4、法一:

將鍊錶a的尾節點的next指標指向鍊錶b的頭結點,從而構造了乙個新鍊錶。問題轉化為求這個新鍊錶是否有環的問題。

時間複雜度為環是否存在的時間複雜度,即o(length(a)+length(b)),使用了兩個額外指標

法二:兩個鍊錶相交,則從相交的節點起,其後的所有的節點都是都是兩個鍊錶共有的。因此,如果它們相交,則最後乙個節點一定是共有的。因此,判斷兩鍊錶相交的方法是:遍歷第乙個鍊錶,記住最後乙個節點。然後遍歷第二個鍊錶,到最後乙個節點時和第乙個鍊錶的最後乙個節點做比較,如果相同,則相交。

時間複雜度:o(length(a)+length(b)),但是只用了乙個額外指標儲存最後乙個節點

5、將鍊錶a的尾節點的next指標指向鍊錶b的頭結點,從而構造了乙個環。問題轉化為求這個環的入口問題。

時間複雜度:求環入口的時間複雜度

6、分別判斷兩個鍊錶a、b是否有環(注,兩個有環鏈表相交是指這個環屬於兩個鍊錶共有)

如果僅有乙個有環,則a、b不可能相交

如果兩個都有環,則求出a的環入口,判斷其是否在b鍊錶上,如果在,則說明a、b相交。

時間複雜度:「環入口問題的時間複雜度」+o(length(b))

7、分別計算出兩個鍊錶a、b的長度la和lb(環的長度和環到入口點長度之和就是鍊錶長度),參照問題3。

如果la>lb,則鍊錶a指標先走la-lb,鍊錶b指標再開始走,則兩個指標相遇的位置就是相交的第乙個節點。

如果lb>la,則鍊錶b指標先走lb-la,鍊錶a指標再開始走,則兩個指標相遇的位置就是相交的第乙個節點。

時間複雜度:o(max(la,lb))

鍊錶的常見面試題

鍊錶的基本操作 逆序列印單鏈表 刪除鍊錶的非尾結點,要求 不能遍歷鍊錶 在鍊錶pos位置前插入值到data的結點 查詢鍊錶的中間結點,要求只能遍歷一次鍊錶 查詢鍊錶的倒數第k個結點,要求只能遍歷一次鍊錶 刪除鍊錶的倒數第k個結點,要求只能遍歷一次鍊錶 用單鏈表實現約瑟夫環 鍊錶的逆置 三個指標 鍊錶...

常見面試題

1.get和post的區別 1 本質區別 get是向伺服器請求資料,post是向伺服器傳送資料。2 伺服器獲取值的方式 get方式提交的資料,伺服器端使用request.querystring獲取變數的值。post方式提交的資料,伺服器端使用request.form獲取資料。3 安全性 get安全效...

常見面試題

1 一行 實現1 100之和 lst i for i in range 1,101 print sum lst 2 如何在乙個函式內部修改全域性變數?在函式內部新增 global 變數名 這樣就可以在本地作用域定義全域性作用域了 name 大明 def eat name1 global name n...