持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,点击查看活动详情
删除链表的倒数第n个节点
题目
19. 删除链表的倒数第 N 个结点
难度中等
给你一个链表,删除链表的倒数第 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]
长度解法
好像大部分题目都有着属于自己的暴力解法,但这个题的简单解法我不想说,因为它复杂且没有意义,甚至于我第一时间想到的解法不是长度解法,而是双指针。
我在数据结构课上曾经写过用长度解决链表的解法程序,但是给老师验收的时候,老师给我发出了灵魂质问:既然是链表的题,为什么要数组化呢? 事实就是那个题用链表解决的算法更加简洁且易读。我受益良多。
双指针
这是我想到的第一解法,即用左右两个指针,先将右指针移动n(这个n就是传入的倒数第n个节点)个节点,然后再将左右指针一起移动,直至没有节点,然后将左指针left.next=left.next.next。这样节点就删除了(没有变量指向它)。
来看程序
function removeNthFromEnd(head: ListNode | null, n: number): ListNode | null {
const h1 = new ListNode(0, head);
//为什么要新建h1? 我先前没有用h1 吃了大亏,花了很多时间
//一是假设2个节点 n=2 那么需要删除首节点 这是我们就需要h1 来进行删除首节点的操作。
//其实就是拉开n个节点差
//二是作为返回值
let left = h1;
let right = head;
let i = 0;
while (i < n) {
right = right?.next as ListNode;
//右指针移动n
i++;
}
while (right !== null) {
//当还有节点的时候移动。
right = right?.next as ListNode;
left = left?.next as ListNode;
}
//ts写链表不太方便,以后碰到链表就用js写了
let p = left;
(left as ListNode).next = p?.next?.next as ListNode;
//将left的next跳过一个节点。
return h1.next;
}
栈存储节点、
这是妙解法,listNode往往都是和队列或栈结合在一起的,这个题也可以用栈来解决。
const r = (l: ListNode | null, n: number) => {
let h1: ListNode = new ListNode(0, l);
let p: ListNode = h1;
let arr: ListNode[] = [];
while (p != null) {
arr.push(p);
p = p.next as ListNode;
}
for (let i = 0; i < n; i++) {
arr.pop();
// pop就可以类似于删除操作,那么pop其实就是删除n个节点。
}
let left = arr[arr.length - 1];
// 最后一个元素就是left,它的next就是被删的n节点
left.next = left.next?.next as ListNode;
return h1.next;
};
总结
本次文章的难点在于节点边界判断以及新建链表的思维,也包括栈和链表的结合。
结语
本次的文章到这里就结束啦!♥♥♥读者大大们认为写的不错的话点个赞再走哦 ♥♥♥
每天一个知识点,每天都在进步!♥♥