經典面試題 鍊錶的相交與環問題

2021-08-31 16:30:42 字數 3756 閱讀 7328

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!

1、 給出兩個單向鍊錶的頭指標phead1和phead2,判斷這兩個鍊錶是否相交。假設兩個鍊錶均不帶環。

示意圖如下:

如果兩個鍊錶相交於某一節點,那麼在這個相交節點之後的所有節點都是兩個鍊錶所共有的。也就是說,如果兩個鍊錶相交,那麼最後乙個節點肯定是共有的。先遍歷第乙個鍊錶,記住最後乙個節點,然後遍歷第二個鍊錶,到最後乙個節點時和第乙個鍊錶的最後乙個節點做比較,如果相同,則相交,否則不相交。時間複雜度為o( len1 + len2),因為只需要乙個額外指標儲存最後乙個節點位址,空間複雜度為o(1)。(程式設計之美上面有詳細的介紹)

2、給出乙個單向鍊錶的頭指標phead,判斷鍊錶中是否有環。

示意圖如下:

鍊錶中有環,其實也就是自相交。我們用兩個指標pslow和pfast從頭開始遍歷鍊錶,pslow每次前進乙個節點,pfast每次前進兩個結點,若存在環,則pslow和pfast肯定會在環中相遇,若不存在,則pslow和pfast能正常到達最後乙個節點(實際上是到達null)。

**如下:

// 判斷鍊錶中是否有環

bool

i***itloop

(linklist *head)

return

false;    // 沒有環}

3、給出兩個單向鍊錶的頭指標phead1和phead2,判斷這兩個鍊錶是否相交,若相交返回第乙個相交的節點。假設兩個鍊錶均不帶環。

方法一:

判斷兩個鍊錶中是否存在位址一致的節點,就可以知道是否相交了。可以對第乙個鍊錶的節點位址進行hash排序,建立hash表,然後針對第二個鍊錶的每個節點的位址查詢hash表,如果它在hash表中出現,則說明兩個鍊錶有共同的結點。這個方法的時間複雜度為:o(max(len1+len2);但同時還得增加o(len1)的儲存空間儲存雜湊表。這樣減少了時間複雜度,增加了儲存空間。

以鍊錶節點位址為值,遍歷第乙個鍊錶,使用hash儲存所有節點位址值,結束條件為到最後乙個節點(無環)或hash中該位址值已經存在(有環)。

方法二:

對第乙個鍊錶遍歷,計算長度len1,同時儲存最後乙個節點的位址。

對第二個鍊錶遍歷,計算長度len2,同時檢查最後乙個節點是否和第乙個鍊錶的最後乙個節點相同,若不相同,則不相交,程式結束。

若相交,兩個鍊錶均從頭節點開始,假設len1大於len2,那麼將第乙個鍊錶先遍歷len1-len2個節點,此時兩個鍊錶當前節點到第乙個相交節點的距離就相等了,比較下乙個節點是不是相同,如果相同就返回該節點(即相交節點),若不相同,兩個鍊錶都同步向後走一步,繼續比較。

示意圖如下:

方法三:

由於兩個鍊錶都沒有環,我們可以把第二個鍊錶接在第乙個鍊錶的後面,如果得到的鍊錶有環,則說明這兩個鍊錶相交。否則,這兩個鍊錶不相交。這樣我們就把問題轉化為判斷乙個鍊錶是否有環了。最後,當然可別忘記恢復原來的狀態,去掉從第乙個鍊錶到第二個煉表表頭的指向。

4、給出乙個單向鍊錶的頭指標phead,判斷鍊錶中是否有環,若存在,則求出進入環中的第乙個節點。

示意圖如下:

紅色虛線框中的節點為待求節點。

首先使用第2個題目中的快、慢指標來判斷鍊錶是否存在環,若不存在結束。

若煉表中存在環,我們從煉表頭、與兩個指標的相遇點分別設乙個指標,每次各走一步,兩個指標必定相遇,且相遇的第乙個點為環的入口點。

**如下:

// 找到環的第乙個入口點

linklist* findloopport

(linklist *head)

if(pfast == null || pfast->next == null)    // 不存在環

return

null; pslow = head; while(pslow != pfast)  return pslow;       // 返回環的入口點}

分析:當pfast若與pslow相遇時,pslow肯定沒有走遍歷完鍊錶,而pfast已經在環內迴圈了n圈(1<=n)。假設pslow走了s步,則pfast走了2s步(pfast步數還等於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)迴圈內環+相遇點到環入口點,於是我們從煉表頭、與相遇點分別設乙個指標,每次各走一步,兩個指標必定相遇,且相遇第一點為環入口點。

小結:鍊錶是資料結構中最基本的,也是面試中常考的,與鍊錶相關的題目也變化多端,只要基礎紮實,多積累一些處理類似問題的技巧,面試時便能應對自如。

單鏈表的的歸併排序,同樣需要找到鍊錶的中間節點,可以使用前面的這個快、慢指標的方法。

typedef

struct

lnodelnode , *linklist;// 對兩個有序的鍊錶進行遞迴的歸併

linklist mergelist_recursive

(linklist head1 , linklist head2)

else  return result;}// 對兩個有序的鍊錶進行非遞迴的歸併

linklist mergelist

(linklist head1 , linklist head2)

else     }  else     else     } } if(head1)  result->next = head1; if(head2)  result->next = head2; return head;}// 歸併排序,引數為要排序的鍊錶的頭結點,函式返回值為排序後的鍊錶的頭結點

linklist mergesort

(linklist head)

else   fast = fast->next; }*/

while(fast->next != null && fast->next->next != null)   if(slow->next == null)    // 鍊錶中只有乙個節點

return r_head; fast = slow->next; slow->next = null; slow = head; // 函式mergelist是對兩個有序鍊錶進行歸併,返回值是歸併後的鍊錶的頭結點

//r_head = mergelist_recursive(mergesort(slow) , mergesort(fast)); r_head = mergelist(mergesort(slow) , mergesort(fast)); return r_head;}

給我老師的人工智慧教程打call!

經典面試題 鍊錶的相交與環問題

出處 1.給出兩個單向鍊錶的頭指phead1和phead2,判斷這兩個鍊錶是否相交。假設兩個鍊錶均不帶環。示意圖如下 如果兩個鍊錶相交於某一節點,那麼在這個節點之後的所有節點都是兩個鍊錶所共有的。那麼也就是說,如果兩個鍊錶相交,那麼最後乙個節點肯定是共有的。先遍歷第乙個鍊錶,記住最後乙個節點,然後遍...

鍊錶的相交與環存在問題

如果兩個鍊錶相交於某一節點,那麼在這個相交節點之後的所有節點都是兩個鍊錶所共有的。也就是說,如果兩個鍊錶相交,那麼最後乙個節點肯定是共有的。先遍歷第乙個鍊錶,記住最後乙個節點,然後遍歷第二個鍊錶,到最後乙個節點時和第乙個鍊錶的最後乙個節點做比較,如果相同,則相交,否則不相交。時間複雜度為o len1...

面試題 判斷鍊錶是否相交

今天看了 july的一篇經典文章 程式設計師程式設計藝術 第九章 閒話鍊錶追趕問題 因為現在一直複習資料結構有關鍊錶的演算法,順便總結下,學習下july大牛的判斷鍊錶是否相交。出處 題目 給出兩個單向鍊錶的頭指標,判斷是否相交。下面是july文章上面的解法 分析 這是來自程式設計之美上的微軟亞院的一...