19. 删除链表的倒数第 N 个结点
一、栈
1、设置一个哑节点,避免删除头节点的问题。构成新的链表 2、遍历新的链表,然后将节点压入栈中。 3、从栈顶弹出n个元素。那么再从栈顶弹出元素的时候,就是被删除节点的前一个节点pre。 4、根据pre节点删除倒数第n个元素。
二、需要注意的事项
1、要删除节点 y,我们需要知道节点 y 的前驱节点 x,并将 x 的指针指向 y 的后继节点。但由于头节点不存在前驱节点,因此我们需要在删除头节点时进行特殊判断。但如果我们添加了哑节点,那么头节点的前驱节点就是哑节点本身,此时我们就只需要考虑通用的情况即可。 2、对于被删除节点的空间释放问题,需要考虑。 设置哑节点之后,需要把遍历的指针放着这个上面,才能避免删除头节点的问题
三、代码实现
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @param {number} n
* @return {ListNode}
*/
var removeNthFromEnd = function(head, n) {
// 设置一个哑节点
let dummyNode = new ListNode(-1);
dummyNode.next = head;
let cur = dummyNode; // 使用cur指针从哑节点开始遍历链表
// 定义一个栈,用来存放链表中的节点
let stack = [];
// 遍历整个链表,将节点放到栈中
while(cur){
stack.push(cur);
cur = cur.next;
}
// 从栈顶弹出n个元素,
for(let i=0;i<n;i++){
stack.pop();
}
// 此时再弹出一个元素就是被删除节点的前一个节点
let prev = stack.pop();
prev.next = prev.next.next; // 删除倒数第n个元素
return dummyNode.next;
};
四、双指针实现
var removeNthFromEnd = function(head, n) {
let dummyHead = new ListNode(-1,head)
let pre = head, count = 0
// 得到链表的长度
while(pre){
count++
pre = pre.next
}
let cur = dummyHead
// 指针前行到需要删除的节点的前一个节点
for(let i=0;i<=count-n-1;i++){
cur = cur.next
}
cur.next = cur.next.next
return dummyHead.next
};