题目
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
示例 1:
输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]
示例 2:
输入:head = [1], n = 1
输出:[]
示例 3:
输入:head = [1,2], n = 1
输出:[1]
提示:
链表中结点的数目为 sz
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz
进阶:你能尝试使用一趟扫描实现吗?
思路
本题我们可以采用双指针的方式来实现。我们可以定义两个指针,分别为 first 和 second,初始时都指向链表的头节点。我们先将 first 指针向前移动 n 步,然后再同时移动 first 和 second 指针,直到 first 指针到达链表的末尾。此时,second 指针即指向倒数第 n 个节点的前一个节点。最后,我们将 second 的 next 指针指向其 next 的 next,即可删除倒数第 n 个节点。 需要注意的是,如果链表的长度小于等于 n,那么我们需要删除的是链表的头节点,因此需要特殊处理。
- 时间复杂度为 O(n),其中 n 是链表的长度。
- 空间复杂度为 O(1),只需要使用常数个额外的指针变量。
/**
* Definition for singly-linked list.
* class ListNode {
* val: number
* next: ListNode | null
* constructor(val?: number, next?: ListNode | null) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
* }
*/
function removeNthFromEnd(head: ListNode | null, n: number): ListNode | null {
let a = head, b = head;
// a先走n个
for(let i = 0; i < n; i++) {
a = a.next;
}
// 不足n个,删除头节点
if(!a) return head.next;
// a走完,b就是倒数第n个的前一个
while(a.next) {
a = a.next;
b = b.next;
}
b.next = b.next ? b.next.next : null;
return head
};