Python編程題48--刪除鏈表的倒數第 N 個結點

題目

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

例如:

原鏈表轉換爲列表:[1, 2, 3, 4, 5],需要刪除倒數第2個節點
最終的鏈表轉換爲列表:[1, 2, 3, 5]

原鏈表轉換爲列表:[1],需要刪除倒數第1個節點
最終的鏈表轉換爲列表:[]

原鏈表轉換爲列表:[1, 2],需要刪除倒數第1個節點
最終的鏈表轉換爲列表:[1]

已知 鏈表節點的定義、鏈表與列表相互轉換 的代碼如下:

class ListNode:  # 單鏈表
    def __init__(self, val=0, next=None):
        self.val = val  # 鏈表節點上存儲的元素
        self.next = next  # 指向下一個鏈表節點


def list_to_list_node(numbers):  # 將列表轉換爲單向鏈表,並返回鏈表的頭節點
    dummy_head = ListNode(0)
    pre = dummy_head
    for number in numbers:
        pre.next = ListNode(number)
        pre = pre.next
    pre = dummy_head.next
    return pre


def list_node_to_list(node):  # 將單向鏈表轉換爲列表
    result = []
    while node:
        result.append(node.val)
        node = node.next
    return result

實現思路1

  • 要刪除鏈表的倒數第 n 個節點,我們可以先計算出鏈表長度length,然後再進行處理,假設求出鏈表長度length爲5
  • 如果要刪除鏈表的倒數第 2 個節點,也就是第4個節點,此時我們只需要讓鏈表的第 3 個節點,通過 next 指向到第 5 個節點即可
  • 有一種情況,如果要刪除的節點恰好是鏈表的頭節點,這個情況在原鏈表上就不好處理,因爲前面沒有頭節點了,所以,我們統一設置一個虛擬頭節點 dummy_head 進行處理,而 dummy_head 通過 next 指向原鏈表的頭節點就行

代碼實現1

class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
        dummy_head = ListNode(next=head)  # 設置一個虛擬頭節點
        cur1, length = dummy_head, 0
        while cur1 is not None:  # 計算鏈表的長度
            length += 1
            cur1 = cur1.next
        cur2, step = dummy_head, length - 1 - n  # step 表示被刪除節點的前一個位置,減去1是因爲多了一個虛擬頭節點
        while step:
            cur2 = cur2.next
            step -= 1
        cur2.next = cur2.next.next  # 跳過下一個節點,直接指向下下個節點
        return dummy_head.next
  • 時間複雜度:O(n)
  • 空間複雜度:O(1)

實現思路2

  • 使用 雙指針 的方式來實現
  • 設置兩個節點指針:slow、fast,fast先移動 n 位,然後再讓slow、fast同時移動,直到fast指向的下一個節點爲空時,二者均停止移動
  • 此時,slow 指向的是鏈表中要刪除節點的前一個節點,我們只需要讓當前節點通過 next 指向下下個節點即可

代碼實現2

class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
        dummy_head = ListNode(next=head)  # 設置一個虛擬頭節點
        slow, fast = dummy_head, dummy_head  # 設置兩個節點指針
        while n:  # fast先移動 n 步
            fast = fast.next
            n -= 1
        while fast.next is not None:  # slow和fast同時移動,當fast指向空節點退出循環
            fast = fast.next
            slow = slow.next
        slow.next = slow.next.next  # slow指向下下個節點(相當於跳過下一個節點,也就是倒數第N個節點)
        return dummy_head.next
  • 時間複雜度:O(n)
  • 空間複雜度:O(1)

實現思路3

  • 使用 的方式實現,但空間複雜度會變爲 O(n)
  • 定義一個棧 stack,遍歷鏈表,讓所有節點入棧
  • 要刪除鏈表的倒數第 n 個節點,只需讓 stack 執行 n 次出棧操作,此時棧頂就恰好爲待刪除節點的前一個節點
  • 接着讓棧頂節點通過 next 指向下下個節點即可

代碼實現3

class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
        dummy_head = ListNode(next=head)  # 設置一個虛擬頭節點
        cur, stack = dummy_head, []
        while cur is not None:  # 所有節點入棧
            stack.append(cur)
            cur = cur.next
        while n:  # 執行 n 次出棧操作
            stack.pop()
            n -= 1
        cur = stack[-1]  # 獲取棧頂元素,此時棧頂恰好爲待刪除節點的前一個節點
        cur.next = cur.next.next  # 跳過下一個節點,直接指向下下個節點
        return dummy_head.next
  • 時間複雜度:O(n)
  • 空間複雜度:O(n)

更多Python編程題,等你來挑戰:Python編程題彙總(持續更新中……)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章