携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情
LeetCode 19:删除链表的倒数第 N 个结点
题目描述
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
解题思路
思路一:利用栈
我们可以在遍历链表的同时将所有节点依次入栈。根据栈「先进后出」的原则,我们弹出栈的第 n 个节点就是需要删除的节点,并且目前栈顶的节点就是待删除节点的前驱节点。这样一来,删除操作就变得十分方便了。
利用数组实现栈先进后出方法为push---入栈和pop---出栈。
添加一个dummy node(哑节点),它的next 指针指向链表的头节点。这样一来,我们就不需要对头节点进行特殊的判断了。
解题代码如下:
/**
* @param {ListNode} head
* @param {number} n
* @return {ListNode}
*/
var removeNthFromEnd = function(head, n) {
let dummy = new ListNode();
dummy.next = head;
let cur = dummy, stack = [] ;
while (cur !== null) {
stack.push(cur);
cur = cur.next;
}
for (let i = 0; i < n; ++i) {
stack.pop();
}
let prev = stack[stack.length - 1];
prev.next = prev.next.next;
return dummy.next;
}
时间复杂度: O(n);
空间复杂度: O(n);
思路二:利用快慢指针
解析分解:
1.需要删除倒数第n个节点, 那么我们需要知道倒数n-1个节点, 执行删除的操作是node.next=node.next.next, 即将当前节点的next指针指向当前节点的下一个节点的下一个节点;
2. 设置快慢两个指针, 快指针先走n + 1步,然后快慢指针一次走一步,当快指针遍历到链表的末尾时,慢指针就刚好处于倒数第n-1个节点;
3. 执行删除,返回dummy节点的next指针即可
/**
* @param {ListNode} head
* @param {number} n
* @return {ListNode}
*/
var removeNthFromEnd = function(head, n) {
let dummy = new ListNode();
dummy.next = head;
let fast = dummy, slow = dummy;
// 快指针先走n + 1步
for (let i = 0; i <= n; i++) {
fast = fast.next;
}
// 快慢指针一次走一步,直到快指针走到头
while(fast !== null) {
fast = fast.next;
slow = slow.next;
}
slow.next = slow.next.next;
return dummy.next;
};
时间复杂度: O(n);
空间复杂度: O(1);