演算法題9 查詢鍊錶中倒數第k個結點

2021-05-25 09:06:15 字數 1337 閱讀 2177

struct listnode

;分析:為了得到倒數第k個結點,很自然的想法是先走到鍊錶的尾端,再從尾端回溯k步。可是輸入的是單向鍊錶,只有從前往後的指標而沒有從後往前的指標。因此我們需要開啟我們的思路。

既然不能從尾結點開始遍歷這個鍊錶,我們還是把思路回到頭結點上來。假設整個鍊錶有n個結點,那麼倒數第k個結點是從頭結點開始的第n-k-1個結點(從0開始計數)。如果我們能夠得到鍊錶中結點的個數n,那我們只要從頭結點開始往後走n-k-1步就可以了。如何得到結點數n?這個不難,只需要從頭開始遍歷鍊錶,每經過乙個結點,計數器加一就行了。

這種思路的時間複雜度是o(n),但需要遍歷鍊錶兩次。第一次得到鍊錶中結點個數n,第二次得到從頭結點開始的第n -k-1個結點即倒數第k個結點。

如果鍊錶的結點數不多,這是一種很好的方法。但如果輸入的鍊錶的結點個數 很多,有可能不能一次性把整個鍊錶都從硬碟讀入物理記憶體,那麼遍歷兩遍意味著乙個結點需要兩次從硬碟讀入到物理記憶體。我們知道把資料從硬碟讀入到記憶體是非 常耗時間的操作。我們能不能把鍊錶遍歷的次數減少到1?如果可以,將能有效地提高**執行的時間效率。

如果我們在遍歷時維持兩個指標,第乙個指標從鍊錶的頭指標開始遍歷,在第k-1步之前,第二個指標保持不動;在第k-1步開始,第二個指標也開始從鍊錶的頭指標開始遍歷。由於兩個指標的距離保持在k-1,當第乙個(走在前面的)指標到達鍊錶的尾結點時,第二個指標(走在後面的)指標正好是倒數第k個結點。

這種思路只需要遍歷鍊錶一次。對於很長的鍊錶,只需要把每個結點從硬碟匯入到記憶體一次。因此這一方法的時間效率前面的方法要高。

思路一的參考**:

思路二的參考**:

討論:這道題的**有大量的指標操作。在軟體開發中,錯誤的指標操作是大部分問題的根源。因此每個公司都希望程式設計師在操作指標時有良好的習慣,比如使用指標之前判斷是不是空指標。這些都是程式設計的細節,但如果這些細節把握得不好,很有可能就會和心儀的公司失之交臂。

另外,這兩種思路對應的**都含有迴圈。含有迴圈的**經常出的問題是在迴圈結束條件的判斷。是該用小於還是小於等於?是該用k還是該用k-1?由於題目要求的是從0開始計數,而我們的習慣思維是從1開始計數,因此首先要想好這些邊界條件再開始編寫**,再者要在編寫完**之後再用邊界值、邊界值減1、邊界值加1都執行一次(在紙上寫**就只能在心裡執行了)。

擴充套件1:和這道題類似的題目還有:輸入乙個單向鍊錶。如果該鍊錶的結點數為奇數,輸出中間的結點;如果鍊錶結點數為偶數,輸出中間兩個結點前面的乙個。

節點數為偶數時情況基本一樣,只是兩個指標初始乙個指向頭結點,乙個指向1號節點。後乙個指標每次跳兩個節點,前乙個每次只跳乙個節點。 

擴充套件2:判斷乙個單向鍊錶是否有環。

也是用到兩個指標。初始均指向頭節點,乙個步長為1,另乙個步長為2。當再次出現兩個指標相等時,就說明鍊錶中有環。

演算法 查詢鍊錶中倒數第k個節點

題目 輸入乙個單向鍊錶,輸出該鍊錶中倒數第 k個結點。鍊錶的倒數第 0個結點為鍊錶的尾指標。分析 為了得到倒數第 k個結點,很自然的想法是先走到鍊錶的尾端,再從尾端回溯 k步。可是輸入的是單向鍊錶,只有從前往後的指標而沒有從後往前的指標。因此我們需要開啟我們的思路。既然不能從尾結點開始遍歷這個鍊錶,...

查詢鍊錶中倒數第k個結點

輸入乙個單向鍊錶,輸出該鍊錶中倒數第k個結點。鍊錶的倒數第0個結點為鍊錶的尾指標。鍊錶結點定義如下 struct listnode 分析 為了得到倒數第k個結點,很自然的想法是先走到鍊錶的尾端,再從尾端回溯k步。可是輸入的是單向鍊錶,只有從前往後的指標而沒有從後往前的指標。因此我們需要開啟我們的思路...

查詢鍊錶中倒數第k個節點

問題 輸入乙個鍊錶,輸出該鍊錶中倒數第k個節點。為了符合大多數人的習慣,從1開始計數,即鍊錶的尾節點是倒數第1個節點。例如,乙個鍊錶有6個節點,從頭節點開始,它們的值依次是1 2 3 4 5 6。這個鍊錶的倒數第3個節點是值為4的節點,鍊錶節點定義如下 struct listnode 解題思路 由於...