題目:輸入乙個鍊錶,輸出該鍊錶中倒數第k個結點。為了符合大多數人的習慣,本題從1開始計數,即鍊錶的尾結點是倒數第1個結點。例如乙個鍊錶有6個結點,從頭結點開始它們的值依次是1、2、3、4、5、6。這個鍊錶的倒數第3個結點是值為4的結點。
鍊錶的節點定義如下,這裡使用的是c#來定義:
public為了得到倒數第k個結點,很自然的想法是先走到鍊錶的尾端,再從尾端回溯k步。當時,從鍊錶結點的定義可以看出本題中的鍊錶是單向鍊錶,單向鍊錶的結點只有從前往後的指標而沒有從後往前的指標,因此這種思路行不通,它只適用於雙向鍊錶。class
node
public node next
public node(int
data)
public node(int
data, node next)
}
如果鍊錶定義中有指向前乙個節點的指標,那麼此解法是可行的,我們可以修改鍊錶定義:
public假設整個鍊錶有n個結點,那麼倒數第k個結點就是從頭結點開始的第n-k+1個結點。如果我們能夠得到鍊錶中結點的個數n,那我們只要從頭結點開始往後走n-k+1步就可以了。class
node
//指向後乙個節點
public node next
//指向前乙個節點prev
public node prev
public node(int
data)
}
那麼,這裡的重點就在於如何求煉表中節點的個數n,只需要從頭開始遍歷鍊錶,每經過乙個結點,計數器加1就行了。
但是,問題來了:這種思路需要遍歷鍊錶兩次,第一次統計出煉表中結點的個數,第二次才能找到倒數第k個結點。
為了能夠只遍歷一次就能找到倒數第k個節點,可以定義兩個指標:
(1)第乙個指標從鍊錶的頭指標開始遍歷向前走k-1,第二個指標保持不動;
(2)從第k步開始,第二個指標也開始從鍊錶的頭指標開始遍歷;
(3)由於兩個指標的距離保持在k-1,當第乙個(走在前面的)指標到達鍊錶的尾結點時,第二個指標(走在後面的)指標正好是倒數第k個結點。
下圖展示了在有6個結點的鍊錶上找倒數第3個結點的過程:
舉一反三:當我們用乙個指標遍歷鍊錶不能解決問題的時候,可以嘗試用兩個指標來遍歷鍊錶。可以讓其中乙個指標遍歷的速度快一些(比如一次在鍊錶上走兩步),或者讓它先在鍊錶上走若干步。
public上面的**存在3處魯棒性問題:static node findkthtotail(node head, uint
k)
behind =head;
while (ahead.next != null
)
return
behind;
}
(1)輸入的head為空指標。由於**會試圖訪問空指標指向的記憶體,程式崩潰。
解決:在處理前增加判斷空指標的**
(2)輸入的以head為頭結點的鍊錶的結點總數少於k。由於在for迴圈中會在鍊錶上向前走k-1步,仍然會由於空指標造成程式崩潰
。解決
(3)輸入的引數k為0。由於k是乙個無符號整數,那麼在for迴圈中k-1得到的將不是-1,而是4294967295(無符號的0xffffffff)。因此for迴圈執行的次數遠遠超出我們的預計,同樣也會造成程式崩潰
。解決:同(1),在處理前的判斷中也判斷引數k是否為0。
public《劍指offer》這本書另外的一大優點就在於作者以乙個開發老鳥的角度時時刻刻地站在了魯棒性、可維護性、可擴充套件性地角度來告訴即將進入開發一線的菜鳥們做提醒,在開發中需要考慮這些東西,並通過設計測試用例進行單元測試驗證結果。static node findkthtotail(node head, uint
k)
node ahead =head;
node behind = null
;
for (int i = 0; i < k - 1; i++)
else
}behind =head;
while (ahead.next != null
)
return
behind;
}
面試題15 鍊錶中倒數第k個結點
為了實現只遍歷鍊錶一次就能找到倒數第k 個結點,我們可以定義兩 個指標。第乙個指標從鍊錶的頭指標開始遍歷向前走k 1步,第二個指標保持不動 從第k 步開始,第二個指標也開始從鍊錶的頭指標開始遍歷。由於兩個指標的距離保持在k 1 當第乙個 走在前面的 指標到達鍊錶的尾結點時,第二個指標 走在後面的 指...
面試題15 鍊錶中倒數第K個結點
題目 輸入乙個鍊錶,輸出該鍊錶中倒數第k個結點。為了符合大多數人的習慣,本題從1開始計數,即鍊錶的尾結點是倒數第1個結點。例如乙個鍊錶有6個結點,從頭結點開始它們的值依次是1 2 3 4 5 6。這個鍊錶的倒數第3個結點是值為4的結點。看到這道題目,最直觀的想法,就是先算出鍊錶的長度n,然後倒數第k...
面試題15 鍊錶中倒數第K個結點
題目 輸入乙個鍊錶,輸出該鍊錶中倒數第k個結點。為了符合大多數人的習慣,本題從1開始計數,即鍊錶的尾結點是倒數第1個結點。例如乙個鍊錶有6個結點,從頭結點開始它們的值依次是1 2 3 4 5 6。這個鍊錶的倒數第3個結點是值為4的結點。看到這道題目,最直觀的想法,就是先算出鍊錶的長度n,然後倒數第k...