2-1

19.删除链表的倒数第N个节点

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

示例:

给定一个链表: 1->2->3->4->5, 和 n = 2.

当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:

给定的 n 保证是有效的。

进阶:

你能尝试使用一趟扫描实现吗?

**Python most votes solution: **

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def removeNthFromEnd(self, head, n):
        """
        :type head: ListNode
        :type n: int
        :rtype: ListNode
        """
        fast = slow = head
        for _ in range(n):
            fast = fast.next
        if not fast:
            return head.next
        while fast.next:
            fast = fast.next
            slow = slow.next
        slow.next = slow.next.next
        return head

时间复杂度:(O(n))

分析:

  • 整个算法是基于这样一种思路:

    把整个链表分成两段,一段长为n (n=N),另一段长为m,(m+n)等于整个链表的总长度。如下图所示。

为了实现只进行一趟扫描就删除倒数第N个节点,需要用到两个指针:fast和slow。

  • 第一次移动:程序中的for循环用于将fast向右移动n个距离(假设蓝色框左侧为链表的头部,右侧为链表的尾部),此时slow并不移动,为第二次移动做准备。

  • 第二次移动:程序中的while循环用于实现第二次移动,此时的slow和fast是同步移动的。如下图所示。

此时fast将走完剩下的距离m,同时slow也跟随fast向右移动m个距离。

第二次移动之后,fast将指向链表中的最后一个节点,slow将指向倒数第N个节点前面紧邻的一个节点的位置。此时,只需让slow的下一个节点跳过倒数第N个节点(即指向倒数第N个节点后面紧邻的一个节点)的位置,即可把倒数第N个节点删除掉。

  • 这里要注意一种特殊情况:即第一次移动就已经移动到了链表的最后一个节点,此时第二次移动将不再进行,从而无法删除掉倒数第N个节点。一种解决方法是:在第一次移动结束之后,判断fast是否已经移动到了最后一个节点,如果是,则直接return head.next(因为这种情况就相当于是删除链表中的第一个节点);否则执行第二次移动。

  • 程序中修改的是slow,但最终return head就可以,这是因为slow和head指向了同一个链表(slow = fast = head),在这种情况下,fast、slow、head中只要有一个发生变化,都会影响到其他两个的值。

原文地址:https://www.cnblogs.com/tbgatgb/p/11101574.html