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编程题汇总(持续更新中……)
作者:wintest
本文版权归作者和博客园共有,欢迎转载,但必须在文章页面明显位置给出原文链接,并保留此段声明,否则保留追究法律责任的权利。