1. 程式人生 > >LeetCode刷題筆記:刪除連結串列的倒數第N個節點

LeetCode刷題筆記:刪除連結串列的倒數第N個節點

Given a linked list, remove the n-th node from the end of list and return its head.

Example:

Given linked list: 1->2->3->4->5, and n = 2.

After removing the second node from the end, the linked list becomes 1->2->3->5.

Note:

Given n will always be valid.

Follow up:

Could you do this in one pass?

解題思路

由於這道題是查閱瞭解答後才pass的,解答的解釋也非常精煉,這裡就直接把解答貼過來了。

方法一:兩次遍歷法
思路

我們注意到這個問題可以容易地簡化成另一個問題:刪除從列表開頭數起的第 (L - n + 1)(L−n+1) 個結點,其中 LL 是列表的長度。只要我們找到列表的長度 L,這個問題就很容易解決。

演算法

首先我們將新增一個啞結點作為輔助,該結點位於列表頭部。啞結點用來簡化某些極端情況,例如列表中只含有一個結點,或需要刪除列表的頭部。在第一次遍歷中,我們找出列表的長度 L。然後設定一個指向啞結點的指標,並移動它遍歷列表,直至它到達第 (L - n)(L−n) 個結點那裡。我們把第 (L - n)(L−n) 個結點的 next

指標重新連結至第 (L - n + 2)(L−n+2) 個結點,完成這個演算法。


這裡寫圖片描述
圖一.刪除列表中的第L-n+1個元素
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* first = (struct ListNode*)malloc(sizeof(ListNode));
        ListNode* dummy = (struct ListNode*)malloc(sizeof(ListNode));
        first
= head; dummy->next = head; int size = 0; while(first != nullptr) { first = first->next; size += 1; } first = dummy; size -= n; while(size > 0) { first = first->next; size -= 1; } first->next = first->next->next; return dummy->next; } };
複雜度分析
  • 時間複雜度:O(L)
    該演算法對列表進行了兩次遍歷,首先計算了列表的長度L其次找到第(L-n)個結點。操作執行了2L-n步,時間複雜度為O(L)。
  • 空間複雜度:O(L)
    我們只用了常量級的額外空間。
方法二:一次遍歷演算法
演算法

上述演算法可以優化為只使用一次遍歷。我們可以使用兩個指標而不是一個指標。第一個指標從列表的開頭向前移動 n+1 步,而第二個指標將從列表的開頭出發。現在,這兩個指標被 n 個結點分開。我們通過同時移動兩個指標向前來保持這個恆定的間隔,直到第一個指標到達最後一個結點。此時第二個指標將指向從最後一個結點數起的第 n 個結點。我們重新連結第二個指標所引用的結點的 next 指標指向該結點的下下個結點。


這裡寫圖片描述
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* first = (struct ListNode*)malloc(sizeof(ListNode));
        ListNode* second = (struct ListNode*)malloc(sizeof(ListNode));
        ListNode* dummy = (struct ListNode*)malloc(sizeof(ListNode));
        dummy->next = head;
        first = dummy;
        second = dummy;

        for(int i = 1; i <= n + 1; ++i) {
            first = first->next;
        }

        while(first != nullptr) {
            first = first->next;
            second = second->next;
        }
        second->next = second->next->next;

        return dummy->next;
    }
};
複雜度分析
  • 時間複雜度:O(L)
    該演算法對含有L個子節點的列表進行了一次遍歷。因此時間複雜度為O(L)。
  • 空間複雜度
    我們只用了常量級的額外空間。