面试题整理 2:求链表倒数第 k 个结点
生活随笔
收集整理的這篇文章主要介紹了
面试题整理 2:求链表倒数第 k 个结点
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
注意問題:想好思路,注意空指針問題;當節點數<k時;當k=0時;邊界的處理問題。 注意輸入參數鏈表頭指針是指向指針的指針。
ListNode* FindKthToTail(ListNode** pListHead, unsigned int k) { if( pListHead == NULL || *pListHead == NULL || k == 0 ) return NULL; ListNode *pAhead = *pListHead; ListNode *pBehind = NULL; for(unsigned int i = 0; i < k - 1; ++ i) { pAhead = pAhead->m_pNext; if(pAhead == NULL) return NULL; } pBehind = *pListHead; while(pAhead->m_pNext != NULL) { pAhead = pAhead->m_pNext; pBehind = pBehind->m_pNext; } return pBehind; }
題目:輸入一個單向鏈表,輸出該鏈表中倒數第 k 個結點。鏈表的倒數第 0 個結點為鏈表的尾指針。?
鏈表結點定義如下: ?
struct ListNode { int m_nKey; ListNode* m_pNext; };分析:為了得到倒數第 k 個結點,很自然的想法是先走到鏈表的尾端,再從尾端回溯 k 步。可是輸入的是單向鏈表,只有從前往后的指針而沒有從后往前的指針,怎么辦?
(1)假設整個鏈表有 n個結點,那么倒數第 k 個結點是從頭結點開始的第 n-k-1 個結點(從 0 開始計數)。如果我們能夠得到鏈表中結點的個數 n,那我們只要從頭結點開始往后走 n-k-1 步就可以了。如何得到結點數 n?只需要從頭開始遍歷鏈表,每經過一個結點,計數器加一就行了。??
這種思路的時間復雜度是 O(n),但需要遍歷鏈表兩次。第一次得到鏈表中結點個數 n,第二次得到從頭結點開始的第 n-k-1 個結點即倒數第 k 個結點。?
如果鏈表的結點數不多,這是一種很好的方法。但如果輸入的鏈表的結點個數很多,有可能不能一次性把整個鏈表都從硬盤讀入物理內存,那么遍歷兩遍意味著一個結點需要兩次從硬盤讀入到物理內存。我們知道把數據從硬盤讀入到內存是非常耗時間的操作。我們能不能把鏈表遍歷的次數減少到 1?如果可以,將能有效地提高代碼執行的時間效率。 (2)如果我們在遍歷時維持兩個指針,第一個指針從鏈表的頭指針開始遍歷,在第 k-1步之前,第二個指針保持不動;在第 k-1 步開始,第二個指針也開始從鏈表的頭指針開始遍歷。由于兩個指針的距離保持在 k-1,當第一個(走在前面的)指針到達鏈表的尾結點時,第二個指針(走在后面的)指針正好是倒數第 k 個結點。? 這種思路只需要遍歷鏈表一次。對于很長的鏈表,只需要把每個結點從硬盤導入到內存一次。因此這一方法的時間效率前面的方法要高。?注意問題:想好思路,注意空指針問題;當節點數<k時;當k=0時;邊界的處理問題。 注意輸入參數鏈表頭指針是指向指針的指針。
ListNode* FindKthToTail(ListNode** pListHead, unsigned int k) { if( pListHead == NULL || *pListHead == NULL || k == 0 ) return NULL; ListNode *pAhead = *pListHead; ListNode *pBehind = NULL; for(unsigned int i = 0; i < k - 1; ++ i) { pAhead = pAhead->m_pNext; if(pAhead == NULL) return NULL; } pBehind = *pListHead; while(pAhead->m_pNext != NULL) { pAhead = pAhead->m_pNext; pBehind = pBehind->m_pNext; } return pBehind; }
總結
以上是生活随笔為你收集整理的面试题整理 2:求链表倒数第 k 个结点的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《深度探索C++对象模型》--5 构造析
- 下一篇: C++ exception