1. 程式人生 > >【LeetCode題解】19_刪除連結串列的倒數第N個節點(Remove-Nth-Node-From-End-of-List)

【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 N+1 個節點,然後將該節點的 next 指標執行倒數第 N

1 N - 1 個節點。 為了找到倒數第 N + 1 N + 1 個節點,我們必須藉助一把長度可變尺子——雙指標。

具體的做法如下:

第 0 步(準備階段)

:為了方便對頭節點進行刪除,統一刪除節點的操作,我們建立一個虛擬的頭節點,接著,再建立兩個指標(p1p2)指向虛擬頭節點;

在這裡插入圖片描述

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

在這裡插入圖片描述

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

在這裡插入圖片描述

最後,我們只需要操作 p1 指標的 next 引用,使得它指向倒數第 N 1 N - 1 個節點即可實現對於倒數第 N 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 ) O(n) ,其中 n n 表示連結串列的長度。首先需要 N N 次操作將 p2 指標移動到第 N N 個節點;接著,需要 2 × ( n N ) 2 \times (n-N) 次操作將 p2 指標移動到連結串列尾部,同時將p1 移動到倒數第 N + 1 N + 1 個節點。因此,總的時間複雜度是 O ( n ) O(n) 的。
  • 空間複雜度 O ( 1 ) O(1)