目錄
題目:
輸入一個鏈表,輸出該鏈表中倒數第k個節點,爲了符合大多數人的習慣,本題從1開始計數,即鏈表的尾節點是倒數第一個節點。例如,一個鏈表有6個節點,從頭節點開始,他們的值依次是1、2、3、4、5、6。這個鏈表的倒數第3個節點是值爲4的節點。鏈表節點定義如下:struct ListNode
{
int m_nValue;
ListNode m_pNext;
}
思路:
假設整個鏈表有n個節點,那麼倒數第k個節點就是從頭節點開始的第n-k+1個節點。如果我們能夠得到鏈表中節點的個數n,那麼只要從頭節點開始往後走n-k+1步就可以了。如何得到節點n?這個不難,只需要從頭節點開始遍歷鏈表,每經過一個節點,計數器加1就可以了。也就是說我們需要遍歷鏈表兩次,第一次統計出鏈表中節點的個數,第二次就能找到倒數第k個節點。但是當我們把這種思路解釋給面試官之後,他會告訴我們他期待的解法只需要遍歷鏈表一次。
爲了實現只遍歷鏈表一次就能找到倒數第k個節點,我們可以定義兩個指針。第一個指針從鏈表的頭指針開始遍歷向前走k-1步,第二個指針保持不動;從第k步開始,第二個指針也開始從鏈表的頭指針開始遍歷。由於兩個指針的距離保持在k-1,當第一個(走在最前面)指針到達鏈表的尾節點時,第二個(走在最後面)指針正好指向倒數第k個節點。
步驟
1.首先用第一個指針從頭節點開始向前走兩(2=3-1)步到達第3個節點。 2.接着把第二個指針初始化指向鏈表的第一個節點。 3.最後讓兩個指針同時向前遍歷,當第一個指針到達鏈表的尾節點時,第二個指針指向的剛好就是倒數第3個節點。代碼:
package test;
public class FindKthToTail {
public static void main(String[] args) {
ListNode ln1 = new ListNode();
ListNode ln2 = new ListNode();
ListNode ln3 = new ListNode();
ListNode ln4 = new ListNode();
ListNode ln5 = new ListNode();
ListNode ln6 = new ListNode();
ln1.value = 1;
ln1.next = ln2;
ln2.value = 2;
ln2.next = ln3;
ln3.value = 3;
ln3.next = ln4;
ln4.value = 4;
ln4.next = ln5;
ln5.value = 5;
ln5.next = ln6;
ln6.value = 6;
ln6.next = null;
System.out.println(findKthToTail(ln1, 3).value);
}
public static ListNode findKthToTail(ListNode pListHead, int k) {
//1.校驗數據的合法性
if(pListHead == null || k == 0) {
return null;
}
ListNode pAhead = pListHead;
ListNode pBehind = null;
//2.將p1指針移動k-1個位置
for (int i = 0; i < k - 1; i++) {
if(pAhead.next != null)
pAhead = pAhead.next;
else
return null;
}
//3.將p2指針從頭節點開始移動直到p1指針到達尾節點
pBehind = pListHead;
while(pAhead.next != null) {
pAhead = pAhead.next;
pBehind = pBehind.next;
}
return pBehind;
}
static class ListNode {
int value;
ListNode next;
}
}