[LeetCode] 203. 移除链表元素

1. 问题描述

203. 移除链表元素 - 力扣(LeetCode)


2. 实现思路

2.1 自己的思路

~~(一定要写出来啊喂)~

题目很简单,删除链表中所有特定值的元素即可,观察测试用例发现,删除的目标值可能在开头,可能在中间,也可能在末尾,那么我们先找到trueHead(也就是val不为目标值的项,再遍历即可)

利用了下C#的?.语法防止NRE

// @lc code=start
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     public int val;
 *     public ListNode next;
 *     public ListNode(int val=0, ListNode next=null) {
 *         this.val = val;
 *         this.next = next;
 *     }
 * }
 */
public class Solution
{
    public ListNode RemoveElements(ListNode head, int val)
    {
        if (head == null) return null;
        ListNode trueHead = head;
        while (trueHead.val == val)
        {
            if (trueHead.next != null)
            {
                trueHead = trueHead.next;
            }
            else return null;
        }

        ListNode node = trueHead;
        while (node != null)
        {
            if (node.next?.val == val)
            {
                node.next = node.next.next ?? null;
                continue;
            }
            node = node.next;
        }
        return trueHead;
    }
}
// @lc code=end

2.2 题解思路

203.移除链表元素 | 链表 | 虚拟头节点

  • 方法一:直接删除

删除节点的核心是,直接让节点next指针指向下个节点即可

但移除头节点的方式稍微有些不同,头节点没有前置节点,因此将头节点向后移一位即可

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        // 删除头结点
        while (head != NULL && head->val == val) { // 注意这里不是if
            ListNode* tmp = head;
            head = head->next;
            delete tmp;
        }

        // 删除非头结点
        ListNode* cur = head;
        while (cur != NULL && cur->next!= NULL) {
            if (cur->next->val == val) {
                ListNode* tmp = cur->next;
                cur->next = cur->next->next;
                delete tmp;
            } else {
                cur = cur->next;
            }
        }
        return head;
    }
};
  • 时间复杂度: O(n)

  • 空间复杂度: O(1)

  • 方法二:虚拟头节点

但是有没有方法可以将两个逻辑合并呢?方法就是加一个虚拟头节点,这样删除头节点的方式就和删除中间节点相同了

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode* dummyHead = new ListNode(0); // 设置一个虚拟头结点
        dummyHead->next = head; // 将虚拟头结点指向head,这样方便后面做删除操作
        ListNode* cur = dummyHead;
        while (cur->next != NULL) {
            if(cur->next->val == val) {
                ListNode* tmp = cur->next;
                cur->next = cur->next->next;
                delete tmp;
            } else {
                cur = cur->next;
            }
        }
        head = dummyHead->next;
        delete dummyHead;
        return head;
    }
};
  • 时间复杂度: O(n)

  • 空间复杂度: O(1)

  • 方法三:递归

基础情况:对于空链表,不需要移除元素。

递归情况:首先检查头节点的值是否为 val,如果是则移除头节点,答案即为在头节点的后续节点上递归的结果;如果头节点的值不为 val,则答案为头节点与在头节点的后续节点上递归得到的新链表拼接的结果。

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        // 基础情况:空链表
        if (head == nullptr) {
            return nullptr;
        }

        // 递归处理
        if (head->val == val) {
            ListNode* newHead = removeElements(head->next, val);
            delete head;
            return newHead;
        } else {
            head->next = removeElements(head->next, val);
            return head;
        }
    }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

2.3 优化(或者敲一遍题解?)


理解了虚拟头节点后敲的,可以感觉出简洁了很多

// @lc code=start
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     public int val;
 *     public ListNode next;
 *     public ListNode(int val=0, ListNode next=null) {
 *         this.val = val;
 *         this.next = next;
 *     }
 * }
 */
public class Solution
{
    public ListNode RemoveElements(ListNode head, int val)
    {
        var dummyNode = new ListNode(0, head);
        var temp = dummyNode;
        while (temp.next != null)
        {
            if (temp.next.val == val)
            {
                temp.next = temp.next.next ?? null;
                continue;
            }
            temp = temp.next;
        }
        return dummyNode.next;
    }
}
// @lc code=end

然后是递归:

// @lc code=start
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     public int val;
 *     public ListNode next;
 *     public ListNode(int val=0, ListNode next=null) {
 *         this.val = val;
 *         this.next = next;
 *     }
 * }
 */
public class Solution
{
    public ListNode RemoveElements(ListNode head, int val)
    {
        if (head == null) return null;

        if (head.val == val)
        {
            var newHead = RemoveElements(head.next, val);
            return newHead;
        }
        else
        {
            head.next = RemoveElements(head.next, val);
            return head;
        }
    }
}
// @lc code=end

3. 补充知识と杂谈,总结

主要知识点是虚拟头节点

posted @ 2026-08-10 12:51  绘星tsuki  阅读(7)  评论(0)    收藏  举报