【LeetCode題解】19_刪除鏈表的倒數第N個節點(Remove-Nth-Node-From-End-of-List)

目錄

更多 LeetCode 題解筆記可以訪問我的 github

描述

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

示例

給定一個鏈表: 1->2->3->4->5, 和 n = 2.

當刪除了倒數第二個節點後,鏈表變爲 1->2->3->5.

說明

給定的 n 保證是有效的。

進階

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

解法:雙指針

思路

求解這道問題等價於尋找倒數的第 \(N+1\) 個節點,然後將該節點的 next 指針執行倒數第 \(N - 1\) 個節點。 爲了找到倒數第 \(N + 1\) 個節點,我們必須藉助一把長度可變尺子——雙指針。

具體的做法如下:

第 0 步(準備階段):爲了方便對頭節點進行刪除,統一刪除節點的操作,我們創建一個虛擬的頭節點,接着,再創建兩個指針(p1p2)指向虛擬頭節點;

第一步:將 p2 指針移動 \(N\) 步,此時,p2 指針位於第 \(N\) 個節點,兩個指針之間的長度爲 \(N + 1\),這就是我們的尺子;

第二步:移動我們的尺子(同時移動兩個指針),直到 p2 指針到達鏈表的尾部,此時,p1 指針的 next 引用所指向的正是倒數第 \(N\) 個節點;

最後,我們只需要操作 p1 指針的 next 引用,使得它指向倒數第 \(N - 1\) 個節點即可實現對於倒數第 \(N\) 個節點的刪除操作。

Java 實現

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        if (head == null || head.next == null) {
            return null;
        }
        
        // 創建一個虛擬頭節點
        ListNode dummy = new ListNode(-1);
        dummy.next = head;

        // 創建兩個指針,並將p2指針移動n步
        ListNode p1 = dummy, p2 = dummy;
        for (int i = 0; i < n; ++i) {
            p2 = p2.next;
        }

        // 移動兩個指針直到p2處於鏈表尾部
        while (p2.next != null) {
            p1 = p1.next;
            p2 = p2.next;
        }
        
        // 刪除第n個節點
        // ListNode nthNode = p1.next;
        p1.next = p1.next.next;
        // nthNode.next = null;
        
        return dummy.next;
    }
}
// Runtime: 6 ms
// Your runtime beats 100.00 % of java submissions.

Python 實現

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def removeNthFromEnd(self, head, n):
        """
        :type head: ListNode
        :type n: int
        :rtype: ListNode
        """
        if not head or not head.next:
            return None
        
        # 創建虛擬頭節點
        dummy = ListNode(-1)
        dummy.next = head
        
        # 創建兩個指針,並將指針p2移動n步
        p1, p2 = dummy, dummy
        for i in range(n):
            p2 = p2.next
            
        # 同時移動兩個指針,直到p2位於鏈表的尾部
        while p2.next:
            p1, p2 = p1.next, p2.next
            
        # 刪除倒數第n個節點
        p1.next = p1.next.next
        
        return dummy.next
# Runtime: 36 ms
# Your runtime beats 100.00 % of python3 submissions.

複雜度分析

  • 時間複雜度\(O(n)\),其中 \(n\) 表示鏈表的長度。首先需要 \(N\) 次操作將 p2 指針移動到第 \(N\) 個節點;接着,需要 \(2 \times (n-N)\) 次操作將 p2 指針移動到鏈表尾部,同時將p1 移動到倒數第 \(N + 1\) 個節點。因此,總的時間複雜度是 \(O(n)\) 的。
  • 空間複雜度\(O(1)\)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章