持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第17天,点击查看活动详情
题目描述
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例1:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
示例 2:
输入: head = [1], n = 1
输出: []
示例 3:
输入: head = [1,2], n = 1
输出: [1]
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
题目地址:leetcode-cn.com/problems/re…
解题思路
这里我们可以使用双指针算法,不妨设为指针 A 和 指针 B。指针 A 先移动 n 次, 指针 B 再开始移动。当 A 到达 null 的时候, 指针 B 的位置正好是倒数第 n。这个时候将 B 的指针指向 B 的下下个指针即可完成删除工作。
具体地,初始时 first 和 second 均指向头节点。我们首先使用 first 对链表进行遍历,遍历的次数为 nn。此时,first 和 second 之间间隔了 n−1 个节点,即 first 比 second 超前了 nn 个节点。
在这之后,我们同时使用 first 和 second 对链表进行遍历。当 first 遍历到链表的末尾(即 first 为空指针)时,second 恰好指向倒数第 n 个节点。
步骤:
- 设置虚拟节点 dummyHead 指向 head(简化判断,使得头结点不需要特殊判断)
- 设定双指针 p 和 q,初始都指向虚拟节点 dummyHead
- 移动 q,直到 p 与 q 之间相隔的元素个数为 n
- 同时移动 p 与 q,直到 q 指向的为 NULL
- 将 p 的下一个节点指向下下个节点
代码:
var removeNthFromEnd = function (head, n) {
let i = -1;
const noop = {
next: null,
};
const dummyHead = new ListNode(); // 增加一个dummyHead 简化操作
dummyHead.next = head;
let currentP1 = dummyHead;
let currentP2 = dummyHead;
while (currentP1) {
if (i === n) {
currentP2 = currentP2.next;
}
if (i !== n) {
i++;
}
currentP1 = currentP1.next;
}
currentP2.next = ((currentP2 || noop).next || noop).next;
return dummyHead.next;
};