代码随想录算法训练营第四天(2)|19.删除链表的倒数第N个节点

56 阅读3分钟

题目描述

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

代码示例

from typing import Optional

# 定义单链表节点
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

class Solution:
    def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
        # 创建一个虚拟节点来处理需要移除头节点的边缘情况
        dummy_head = ListNode(val=0, next=head)
        fast_pointer = slow_pointer = dummy_head

        # 将快指针提前移动 n+1 步
        n += 1
        while n > 0 and fast_pointer:
            fast_pointer = fast_pointer.next
            n -= 1

        # 同时移动指针直到快指针到达链表末尾
        while fast_pointer:
            slow_pointer = slow_pointer.next
            fast_pointer = fast_pointer.next

        # 从末尾移除第 n 个节点
        slow_pointer.next = slow_pointer.next.next

        return dummy_head.next

# 示例:创建一个链表并从末尾移除第二个节点
if __name__ == "__main__":
    # 辅助函数:从值列表创建链表
    def create_linked_list(values):
        if not values:
            return None
        head = ListNode(values[0])
        current = head
        for val in values[1:]:
            current.next = ListNode(val)
            current = current.next
        return head

    # 辅助函数:打印链表
    def print_linked_list(head):
        while head:
            print(head.val, end=" -> ")
            head = head.next
        print("None")

    # 创建链表:1 -> 2 -> 3 -> 4 -> 5
    linked_list = create_linked_list([1, 2, 3, 4, 5])
    print("原始链表:")
    print_linked_list(linked_list)

    # 从末尾移除第二个节点
    sol = Solution()
    modified_list = sol.removeNthFromEnd(linked_list, 2)

    # 打印修改后的链表
    print("\n移除节点后的链表:")
    print_linked_list(modified_list)

在面对删除链表倒数第n个节点的问题时,一开始的直观思考是遍历整个链表,找到最后一个节点,然后返回找到对应节点的前一个节点。但是由于这是一个单链表,我们需要提前知道链表的长度,再进行一次遍历找出要删除的节点,并将其移除。

然而,通过学习完整个代码随想录后,我发现可以采用快慢指针的方式来更加巧妙地解决问题。通过让快指针先走n步,然后慢指针开始走,当快指针到达链表末尾时,慢指针正好走到要移除的节点上。这样,我们可以在删除节点之前的节点上进行操作。让快指针先走n+1步,慢指针正好落在移除节点之前的节点上。

在实现过程中遇到的困难是,初始时快指针和慢指针的位置都指向了dummy.next,导致了错误的发生。为了避免这个问题,我修改了初始的指针位置,

总的来说,通过这个问题的学习,我不仅学会了如何使用快慢指针处理链表问题,而且发现了创建dummy_head节点的妙用,简化了链表操作,省去了原有链表中的一些繁琐操作。这次学习让我更深入地理解了链表的操作技巧,也提高了解决类似问题的能力。在学习的过程中,我意识到快慢指针的应用不仅局限于数组,同样可以在链表中发挥巨大的作用。