题目
给定一个链表,删除链表的倒数第 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 个节点,因此我们可以使用两个指针 fast 和 slow 同时对链表进行遍历,并且 fast 比 slow 超前 n 个节点。当 fast 遍历到链表的末尾时,slow 就恰好处于倒数第 n 个节点。
初始时 fast 和 slow 均指向头节点。我们首先使用 fast 对链表进行遍历,遍历的次数为 n。此时,fast 和 slow 之间间隔了 n-1 个节点,即 fast 比 slow 超前了 n 个节点。
在这之后,我们同时使用 fast 和 slow 对链表进行遍历。当 fast 遍历到链表的末尾(即 fast 为空指针)时,slow 恰好指向倒数第 n 个节点。此时问题就变更为删除链表中的slow的后继节点
但存在一个问题,当链表长度为 n 时,fast 是前进不到 n+1 个节点位置的,所以此时应该判断 fast.next 是否为 null ,即 fast 是否是最后一个节点,如果是,则 head 为倒数第 n 个节点,此时问题可以简化为删除头节点;如果不是, fast = fast.next ,fast 再前进一步,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
}