1. 程式人生 > >LeetCode 19——刪除連結串列的倒數第 N 個節點

LeetCode 19——刪除連結串列的倒數第 N 個節點

1. 題目

給定一個連結串列,刪除連結串列的倒數第 n 個節點,並且返回連結串列的頭結點。

示例:
給定一個連結串列: 1->2->3->4->5, 和 n = 2.
當刪除了倒數第二個節點後,連結串列變為 1->2->3->5.

說明:
給定的 n 保證是有效的。

進階:
你能嘗試使用一趟掃描實現嗎?

2. 思路

  • 定義兩個指標 p1、p2,剛開始兩個指標都指向頭結點。如果要刪除倒數第 N 個結點,我們就讓 p2 先前進 N-1 步,這時候 p2 後面的節點個數為 K,那我們要刪除的結點也就是位於 p1 後面的第 K 個結點

  • 如下圖所示,假設我們要刪除倒數第 3 個結點,p2 前進 2 步後指向第三個結點。

1.png

  • p2 後面還有 1 個結點,而我們要刪除的結點也就是位於 p1 後面的第 1 個結點——結點 2。

2.png

  • 一種特殊情況是要刪除倒數第 4 個結點,也就是第 1 個結點。這時候,我們只需要讓 head 指向第 2 個結點即可。

3.png

  • 其他情況下,在 p2 指標到達指定位置後。我們先讓 p2 指標後移一個位置,然後再同時讓 p1 和 p2 向後移動。當 p2 指向最後一個結點時,p1 就指向了待刪除節點的前一個結點,此時讓 p1 指向 p1 後面的第 2 個結點即可刪除指定的結點。

  • 以下為刪除倒數第 1 個結點的過程。

4.png

5.png

  • 當然,不要忘了釋放刪除結點的記憶體
  • 程式碼如下
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        
        if (head == NULL)
        {
            return head;
        }

        else
        {
            int i = 1;
            ListNode *p1 = head, *p2 = head, *temp = NULL;
            
            while (i != n) // p2 指標前進 n-1 步
            {
                i++;
                p2 = p2->next;
            }
            
            if (p2->next == NULL) // 刪除第一個結點的情況
            {
                temp = head;
                head = head->next; // head 指向第 2 個結點
            }
            else
            {
                p2 = p2->next; // p2 指標先前進 1 步
            
                while(p2->next)  // p1、p2 指標同步向後移動
                {
                    p2 = p2->next;
                    p1 = p1->next;
                }

                temp = p1->next;
                p1->next = p1->next->next; // p1 指向其後面的第 2 個結點
            }
            
            delete(temp); // 釋放結點記憶體
            
        }   
            
        return head;
            
    }
        
};

獲取更多精彩,請關注「seniusen」!
seniusen