程式設計師面試一百題-09-查詢單向連結串列中倒數第k個結點
阿新 • • 發佈:2018-12-16
1-題目
:
輸入一個單向連結串列
,輸出該連結串列中倒數第k個結點
,連結串列的倒數第0個結點為連結串列的尾指標。
2-思路
:
2.1-錯誤思路
: 為了得到倒數第k個結點,很自然的想法是先走到連結串列的尾端,再從尾端回溯k步,可是單向連結串列只有從前往後的指標而沒有從後往前的指標
。
2.2-正確思路1
: 遍歷連結串列兩次
。第一次得到連結串列中結點個數n,第二次得到從頭結點開始的第n-k-1個結點即倒數第k個結點(從0開始計數)。
2.3-正確思路2
: 如果結點個數很多,可能不能一次性把整個連結串列都從硬碟讀入記憶體,那麼遍歷兩遍意味著一個結點需要兩次從硬碟讀入到記憶體,這是非常耗時間的操作。能不能把連結串列遍歷的次數減少到1?
維持兩個指標
,第一個指標從連結串列的頭指標開始遍歷,在第k-1步之前,第二個指標保持不動;在第k-1步開始,第二個指標也開始從連結串列的頭指標開始遍歷。由於兩個指標的距離保持在k-1,當第一個(走在前面的)指標到達連結串列的尾結點時,第二個指標(走在後面的)指標正好是倒數第k個結點。這種思路只需要遍歷連結串列一次
,對於很長的連結串列,只需要把每個結點從硬碟匯入到記憶體一次。
3-程式碼
(維持兩個指標) :
//連結串列結點的定義 struct ListNode { int m_nKey; ListNode *m_pNext; }; ListNode *FindKthToTail(ListNode *pListHead, unsigned int k) { //若連結串列為空 if (pListHead == NULL) { return NULL; } ListNode *pAhead = pListHead; ListNode *pBehind = NULL; //k步之前,只移動前指標 for (unsigned int i = 0; i < k; i++) { if (pAhead->m_pNext != NULL) { pAhead = pAhead->m_pNext; } else { return NULL; } } //k步之後,前後指標同時移動 pBehind = pListHead; while (pAhead->m_pNext != NULL) { pAhead = pAhead->m_pNext; pBehind = pBehind->m_pNext; } //返回後指標即為倒數第k個結點 return pBehind; }