鏈表的倒數第k個節點


題目

輸入一個鏈表,輸出該鏈表中倒數第k個結點。為了符合大多數人的習慣,本題從1開始計數,即鏈表的尾結點是倒數第1個結點。例如一個鏈表有6個結點,從頭結點開始它們的值依次是1、2、3、4、5、6。這個鏈表的倒數第3個結點是值為4的結點。

解題思路

1.不可行的常規解法

  為了得到倒數第k個結點,很自然的想法是先走到鏈表的尾端,再從尾端回溯k步。當時,從鏈表結點的定義可以看出本題中的鏈表是單向鏈表,單向鏈表的結點只有從前往后的指針而沒有從后往前的指針,因此這種思路行不通,它只適用於雙向鏈表。

  如果鏈表定義中有指向前一個節點的指針,那么此解法是可行的

2.可行但不高效的常規解法

  假設整個鏈表有n個結點,那么倒數第k個結點就是從頭結點開始的第n-k+1個結點。如果我們能夠得到鏈表中結點的個數n,那我們只要從頭結點開始往后走n-k+1步就可以了。

  那么,這里的重點就在於如何求鏈表中節點的個數n,只需要從頭開始遍歷鏈表,每經過一個結點,計數器加1就行了。

  但是,問題來了:這種思路需要遍歷鏈表兩次,第一次統計出鏈表中結點的個數,第二次才能找到倒數第k個結點

3.可行且高效的解法

  為了能夠只遍歷一次就能找到倒數第k個節點,可以定義兩個指針:

  (1)第一個指針從鏈表的頭指針開始遍歷向前走k-1,第二個指針保持不動

  (2)從第k步開始,第二個指針也開始從鏈表的頭指針開始遍歷

  (3)由於兩個指針的距離保持在k-1,當第一個(走在前面的)指針到達鏈表的尾結點時,第二個指針(走在后面的)指針正好是倒數第k個結點

  下圖展示了在有6個結點的鏈表上找倒數第3個結點的過程:

拓展

  1. 當我們用一個指針遍歷鏈表不能解決問題的時候,可以嘗試用兩個指針來遍歷鏈表。可以讓其中一個指針遍歷的速度快一些(比如一次在鏈表上走兩步),或者讓它先在鏈表上走若干步。
  2. 求鏈表的中間節點如果鏈表的結點總數為奇數,返回中間節點,如果鏈表的總數為偶數,返回中間兩個結點中的任意一個也可以定義兩個指針,同時從鏈表的頭出發,一個走一步,一個走兩步,走的快的到表尾時,走得慢的正好是中間結點。
  3. 當用一個指針遍歷鏈表不能解決問題的話,嘗試用兩個鏈表
    /*
    struct ListNode {
        int val;
        struct ListNode *next;
        ListNode(int x) :
                val(x), next(NULL) {
        }
    };*/
    class Solution {
    public:
        ListNode* FindKthToTail(ListNode* head, unsigned int k) {
            if(!head)
                return nullptr;
            
            ListNode *fast=head,*slow=head;
            while(k--) 
            {
                /*果走不到第k步(nullptr節點是可以走到的,但是nullptr節點沒有next,所以只能走到nullptr),
                說明鏈表長度不夠k,直接返回nullptr*/
               if(fast==nullptr)
                   return nullptr;
                fast=fast->next;
            }
            while(fast)
            {
                fast=fast->next;
                slow=slow->next;
            }
            return slow;
        }
    };

解決代碼魯棒性

(1)輸入的head為空指針。由於代碼會試圖訪問空指針指向的內存,程序崩潰

    解決:在處理前增加判斷空指針的代碼

(2)輸入的以head為頭結點的鏈表的結點總數少於k。由於在for循環中會在鏈表上向前走k-1步,仍然會由於空指針造成程序崩潰

    解決:在for循環中增加判斷下一個節點是否是空指針的代碼

(3)輸入的參數k為0。由於k是一個無符號整數,那么在for循環中k-1得到的將不是-1,而是4294967295(無符號的0xFFFFFFFF)。因此for循環執行的次數遠遠超出我們的預計,同樣也會造成程序崩潰


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM