237. 删除链表中的节点
题目描述
有一个单链表,但你拿不到它的头节点 head,只能拿到其中一个要删掉的节点 node。链表里的值互不相同,并且 node 一定不是尾节点。
实现一个没有返回值的函数,把 node 从链表中删掉。这里的删除不是释放内存,而是要满足:链表中不再出现 node 原来的值;节点总数减少 1;node 之前的值和之后的值各自保持原来的先后顺序。
测试时会给出整条链表 head(数组形式)和要删除的节点值 node。系统先建好链表,再把对应节点传给你的函数。输出是函数执行后整条链表的样子。
示例 1
输入:head = [4,5,1,9], node = 5 输出:[4,1,9]
解释:删掉值为 5 的第 2 个节点,链表变为 4 -> 1 -> 9。
示例 2
输入:head = [4,5,1,9], node = 1 输出:[4,5,9]
解释:删掉值为 1 的第 3 个节点,链表变为 4 -> 5 -> 9。
数据范围
- 节点个数在
[2, 1000]之间。 -1000 <= Node.val <= 1000- 链表中每个值只出现一次。
node确实在链表里,并且不是最后一个节点。
解题思路
通常删除节点要改前驱的 next,但这里拿不到前驱。换个思路:把后继 nxt 的值拷贝到 node 上,再把 nxt 从链上摘掉。从值的角度看,node 原来的值消失了,达到了“删除”的效果。
为什么正确
一切只通过 node 和 node.next 完成,前面的节点一个都不碰。
复杂度分析
时间 O(1),额外空间 O(1)。
易错点
真正从内存链上消失的是后继节点,不是 node 这个对象。这也是题目保证 node 不是尾节点的原因:尾节点没有后继可拷贝。
参考代码
Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。
class Solution:
def deleteNode(self, node: ListNode) -> None:
nxt = node.next
node.val = nxt.val
node.next = nxt.nextclass Solution {
public void deleteNode(ListNode node) {
ListNode nxt = node.next;
node.val = nxt.val;
node.next = nxt.next;
}
}class Solution {
public:
void deleteNode(ListNode* node) {
ListNode* nxt = node->next;
node->val = nxt->val;
node->next = nxt->next;
}
};func deleteNode(node *ListNode) {
nxt := node.Next
node.Val = nxt.Val
node.Next = nxt.Next
}var deleteNode = function(node) {
const nxt = node.next;
node.val = nxt.val;
node.next = nxt.next;
};function deleteNode(node: ListNode | null): void {
const nxt = node!.next!;
node!.val = nxt.val;
node!.next = nxt.next;
}