鏈表經典問題匯總

來源:互聯網
上載者:User

收集了一下鏈表常見的面試題:

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 plaincopyprint?
  1. bool IsExitsLoop(slist *head) 
  2.     slist *slow = head, *fast = head; 
  3.  
  4.     while ( fast && fast->next )  
  5.     { 
  6.         slow = slow->next; 
  7.         fast = fast->next->next; 
  8.         if ( slow == fast )
    break; 
  9.     } 
  10.  
  11.     return !(fast == NULL || fast->next == 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);}

時間複雜度分析:假設甩尾(在環外)長度為 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 plaincopyprint?
  1. slist* FindLoopPort(slist *head) 
  2.     slist *slow = head, *fast = head; 
  3.  
  4.     while ( fast && fast->next )  
  5.     { 
  6.         slow = slow->next; 
  7.         fast = fast->next->next; 
  8.         if ( slow == fast )
    break; 
  9.     } 
  10.  
  11.     if (fast == NULL || fast->next == NULL) 
  12.         return NULL; 
  13.  
  14.     slow = head; 
  15.     while (slow != fast) 
  16.     { 
  17.          slow = slow->next; 
  18.          fast = fast->next; 
  19.     } 
  20.  
  21.     return slow; 
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;}

時間複雜度分析:假設甩尾(在環外)長度為 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))

轉自:http://blog.csdn.net/vividonly/article/details/6673758

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.