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

翩若驚鴻,婉若游龍。榮曜秋菊,華茂春鬆。
文章首發於公衆號 「蘑菇睡不着」,更多精彩內容歡迎關注

1、題目描述

給你一個鏈表,刪除鏈表的倒數第 n 個結點,而且返回鏈表的頭結點。 node

示例 1:學習

輸入:head = [1,2,3,4,5], n = 2
輸出:[1,2,3,5]

示例 2:指針

輸入:head = [1], n = 1
輸出:[]

示例 3:code

輸入:head = [1,2], n = 1
輸出:[1]

提示:
鏈表中結點的數目爲 sz
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= szrem

2、思路分析:

  這道題的包含兩個問題:一是:怎麼找到倒數第 N 個節點;二是:怎麼刪除一個節點。
  先說怎麼刪除一個節點吧。其實也很簡單,那就是要被刪除節點的前置節點的next指針,指向被刪除節點的下一個節點便可。代碼片斷爲:node.next = node.next.next;其中 node 爲 被刪除節點的前置節點。
  再說說怎麼找到倒數第 N 個節點。這個就有講頭了,主要有兩種方法:io

  1. 雙指針法:定義兩個快慢指針,快指針先走 N 步,而後快慢指針一塊兒日後走,直到快指針到鏈表末尾。此時,慢指針就是被刪除指針的前置節點,而後怎麼刪除就不用我說了吧。
  2. 利用棧:將鏈表按順序壓入棧中,而後開始往外彈出元素,彈 N 次,彈完 N 次後,在彈出一個元素,這個元素就是 被刪除節點的前置節點。

接下來會用兩端代碼來實現這兩種方法。ast

3、AC代碼

方法一:class

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        if (head == null) {
            return head;
        }
        // 定義啞節點,主要是爲了防止當 頭節點也被刪除的狀況
        ListNode listNode = new ListNode(0, head);
        // 快指針
        ListNode fast = listNode;
        // 慢指針
        ListNode slow = listNode;
        // 快指針先走 N 步
        while(n > 0 && fast.next != null) {
            fast = fast.next;
            n --;
        }
        
        if (n > 0) {
            return listNode.next;
        }
        // 快慢指針一塊兒走
        while(fast.next != null) {
            fast = fast.next;
            slow = slow.next;
        }
        // 若是說被刪除節點是倒數第一個節點,那麼就直接置爲null
        if (slow.next == null || slow.next.next == null)         {
            slow.next = null;
            return listNode.next;
        }
        // 刪除節點
        slow.next = slow.next.next;
        return listNode.next;

    }
}

時間複雜度:O(n),其中 n 是鏈表的長度,要遍歷一次鏈表
空間複雜度:O(1)。List

方法二:遍歷

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(0, head
        // 定義棧
        Deque<ListNode> stack = new LinkedList<ListNode>();
        ListNode cur = dummy;
        // 按順序壓入棧
        while (cur != null) {
            stack.push(cur);
            cur = cur.next;
        }
        // 彈出 N 個元素
        for (int i = 0; i < n; ++i) {
            stack.pop();
        }
        // 在彈出一個(注意這裏是彈出但不刪除節點),做爲被刪除節點的前置節點
        ListNode prev = stack.peek();
        // 刪除節點
        prev.next = prev.next.next;
        ListNode ans = dummy.next;
        return ans;
    }
}

時間複雜度:O(n),其中 n 是鏈表的長度,要遍歷一次鏈表
空間複雜度: O(n),其中 n 是鏈表的長度。主要爲棧的開銷

4、總結

  這道題總體難度還能夠,難點就是要知道如何正確的刪除節點,以及若是正確的找到被刪除的節點。其實刪除節點還有不少辦法,好比:將被刪除節點的next節點的值賦給本身,而後將被刪除節點的next節點刪除也能夠到達所要的效果。

若是以爲文章還不錯就點個贊、關個注唄~

來公衆號:蘑菇睡不着,你們一塊兒學習!
相關文章
相關標籤/搜索