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编程题汇总(持续更新中……)

你可能感兴趣的:(Python编程题48--删除链表的倒数第 N 个结点)