算法:删除链表倒数第 n 个结点

141 阅读1分钟

题目

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

示例 1:

输入: head = [1,2,3,4,5], n = 2
输出: [1,2,3,5]

示例 2:

输入: head = [1], n = 1
输出: []

提示:

链表中结点的数目为 sz

1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz

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

解法:双指针

由于我们需要找到倒数第 n 个节点,因此我们可以使用两个指针 fastslow 同时对链表进行遍历,并且 fastslow 超前 n 个节点。当 fast 遍历到链表的末尾时,slow 就恰好处于倒数第 n 个节点。

初始时 fastslow 均指向头节点。我们首先使用 fast 对链表进行遍历,遍历的次数为 n。此时,fastslow 之间间隔了 n-1 个节点,即 fastslow 超前了 n 个节点。

在这之后,我们同时使用 fastslow 对链表进行遍历。当 fast 遍历到链表的末尾(即 fast 为空指针)时,slow 恰好指向倒数第 n 个节点。此时问题就变更为删除链表中的slow的后继节点

但存在一个问题,当链表长度为 n 时,fast 是前进不到 n+1 个节点位置的,所以此时应该判断 fast.next 是否为 null ,即 fast 是否是最后一个节点,如果是,则 head 为倒数第 n 个节点,此时问题可以简化为删除头节点;如果不是, fast = fast.nextfast 再前进一步,slow为倒数第n+1个节点,也解决了以上问题

var removeNthFromEnd = function(head, n) {
    let fast = head, slow = head
    // 快先走 n 步
    while(--n) {
        fast = fast.next
    }
    if(!fast.next) return head.next
    fast = fast.next
    // fast、slow 一起前进
    while(fast && fast.next) {
        fast = fast.next
        slow = slow.next
    }
    slow.next = slow.next.next
    return head
}