力扣【链表专题】👊 203. 移除链表元素

87 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第 1 天,点击查看活动详情

题目链接

203. 移除链表元素

题目描述

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

测试用例

示例 1:

image.png

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

限制

  • 列表中的节点数目在范围 [0, 104] 内
  • 1 <= Node.val <= 50
  • 0 <= val <= 50

题目分析

题目需要我们移除链表中,具备有给定值的节点。由题目提供的链表结构可以确认,这是一个单向链表,即只能从链表头一路遍历的最后,因此,我们需要一直持有链表头节点的引用

以链表 A -> B -> C 为例,如果我们需要移除节点 B,则需要修改节点 Anext 指向为 C。由于题目提供的链表特性,我们在遍历链表时,如果当前引用已经指向到了节点 B,则无法删除当前节点,我们需要提前一步判定下一个节点是否需要移除,判断的伪代码如下:

if (A.next.val == val){  // A.next 为 B,此刻
    A.next = A.next.next; // 将 A.next 修改引用指向为 C
}

在上面的判断里修改了 A.next 的引用后,我们需要再次为 A.next.val 检查,确认 Anext 指向是否需要继续后移

代码实现

考虑一种特殊的情况,即上开头的节点就是需要我们移除的目标节点,那么链表就需要重置自己的头节点 head = head.next;等重置完成后,就需要为 head.next 做值的判断,这中间会夹杂着不少的判断,代码如下:

var removeElements = function(head, val) {
    if (head == null) return head;
    // 处理开头值相同的情况
    while (head != null && head.val == val) {
        head = head.next;
    }
    let node = head;
    // 正式处理链表中间的目标节点
    for (; node != null && node.next != null;) {
        if (node.next.val == val) {
            node.next = node.next.next;
        } else {
            node = node.next;
        }
    }
    return head;
};

优化

上面的解法略显繁琐,我们可以在头结点之前再添加一个节点,寓意为链表的无含义起始节点 startNode 。随后可以使用上面分析的通用判断即可

/*
function ListNode(val, next) {
    this.val = (val === undefined ? 0 : val)
    this.next = (next === undefined ? null : next)
}
*/
var removeElements = function(head, val) {
    let h = new ListNode(0, head),
        node = h; // 给定一个通用的头结点
    for (; node.next != null;) {
        if (node.next.val == val) {
            node.next = node.next.next;
        } else {
            node = node.next
        }
    }
    return h.next;
};

image.png