題目
給定一個鏈表,請刪除鏈表的倒數第 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編程題彙總(持續更新中……)