刪除鏈表的倒數第N個節點

方法一:兩次遍歷算法

思路

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

算法

首先我們將添加一個啞結點作爲輔助,該結點位於列表頭部。啞結點用來簡化某些極端情況,例如列表中只含有一個結點,或需要刪除列表的頭部。在第一次遍歷中,我們找出列表的長度 L。然後設置一個指向啞結點的指針,並移動它遍歷列表,直至它到達第 (L - n)個結點那裏。我們把第 (L - n)個結點的 next 指針重新鏈接至第 (L - n + 2)個結點,完成這個算法。

public ListNode removeNthFromEnd(ListNode head, int n) {
    ListNode dummy = new ListNode(0);
    dummy.next = head;
    int length  = 0;
    ListNode first = head;
    while (first != null) {
        length++;
        first = first.next;
    }
    length -= n;
    first = dummy;
    while (length > 0) {
        length--;
        first = first.next;
    }
    first.next = first.next.next;
    return dummy.next;
}

複雜度分析

時間複雜度:O(L),該算法對列表進行了兩次遍歷,首先計算了列表的長度 LL 其次找到第 (L - n)個結點。 操作執行了 2L−n 步,時間複雜度爲O(L)。

空間複雜度:O(1)O(1),我們只用了常量級的額外空間。
方法二:一次遍歷算法
算法

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

public ListNode removeNthFromEnd(ListNode head, int n) {
    ListNode dummy = new ListNode(0);
    dummy.next = head;
    ListNode first = dummy;
    ListNode second = dummy;
    // Advances first pointer so that the gap between first and second is n nodes apart
    for (int i = 1; i <= n + 1; i++) {
        first = first.next;
    }
    // Move first to the end, maintaining the gap
    while (first != null) {
        first = first.next;
        second = second.next;
    }
    second.next = second.next.next;
    return dummy.next;
}

複雜度分析
時間複雜度:O(L),該算法對含有 L 個結點的列表進行了一次遍歷。因此時間複雜度爲 O(L)。

空間複雜度:O(1),我們只用了常量級的額外空間。
刷題記錄的代碼:

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
      
        ListNode p =head;
        List<Integer> list = new ArrayList<>();
        while(p!=null){
            list.add(p.val);
            p=p.next;
        }
        
        list.remove(list.size()-n);
        
        if(list.isEmpty()){
            return null;
        }

        ListNode m = null;
        ListNode Nhead = new ListNode(list.get(0));
         m=Nhead;
        for(int i = 1 ;i<list.size();i++){
            ListNode listNode = new ListNode(list.get(i));
            m.next=listNode;
            m=listNode;
        }
        return Nhead;
    }
}

 

發佈了65 篇原創文章 · 獲贊 13 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章