在问 · 算法题解

203. 移除链表元素

简单链表哑结点 + 迭代力扣原题 ↗

题目描述

输入链表头节点 head 和整数 val。删掉链表中所有值等于 val 的节点。

返回删除后链表的头节点;若所有节点都被删掉或链表本来为空,返回 null。

链表以数组形式表示,例如 [1,2,3]。

示例 1
输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]

解释:两个值为 6 的节点被删除。

示例 2
输入:head = [], val = 1
输出:[]

解释:链表本来就是空的。

示例 3
输入:head = [7,7,7,7], val = 7
输出:[]

解释:所有节点的值都是 7,全部删掉后链表为空。

数据范围

  • 节点数在 [0, 10^4] 范围内。
  • 1 <= Node.val <= 50
  • 0 <= val <= 50

解题思路:哑结点 + 迭代

删除一个节点要改它前驱的 next,所以指针 prev 始终停在“待检查节点的前一个”。头节点也可能被删,于是在最前面放一个哑节点 dummy,让每个真实节点都有前驱。prev.next 的值等于 val 就跳过它(prev 不动,因为新接上来的节点还没检查);否则 prev 前进。

为什么正确

dummy 到 prev 这一段已经不含 val;prev.next 是下一个待检查的节点。

复杂度分析

时间 O(n),额外空间 O(1)。

易错点

删除后不要让 prev 前进:新接上来的 prev.next 可能也等于 val(连续相同值)。另外不用哑节点时,要单独处理头部连续被删的情况。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
        dummy = ListNode(0, head)
        prev = dummy
        while prev.next:
            if prev.next.val == val:
                prev.next = prev.next.next
            else:
                prev = prev.next
        return dummy.next

载入编辑器,自己跑一遍 →

其他解法

递归利用子问题“删除剩余链表”从后往前处理;迭代用哑结点统一头结点的情况、从前往后删除,空间 O(1)。

解法 2:递归 时间 O(n),空间 O(n)

先递归删除 head.next 之后链表中的目标值,把结果接回 head.next。然后判断 head 本身:等于 val 就返回 head.next,否则返回 head。空链表直接返回空。

不需要哑结点,头结点和其他结点的处理方式一致,代码很短。递归深度等于链表长度,需要 O(n) 栈空间。

from typing import Optional

class Solution:
    def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
        if head is None:
            return None
        head.next = self.removeElements(head.next, val)
        return head.next if head.val == val else head

链表 专题的其他题目

查看 链表 全部题目 →