移除链表元素(最优解)

题目来源

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


题目描述

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

示例 1:

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

示例 2:

输入:head = [], val = 1
输出:[]

示例 3:

输入:head = [7,7,7,7], val = 7
输出:[]

提示:

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

题目限制

题目用最优解实现求解


思路分析

一、整体思路概述

解决这个问题的核心思路是遍历整个链表,在遍历过程中判断每个节点的值是否等于给定的 val,如果相等,则将该节点从链表中删除,最终返回处理后的链表头节点。不过,在实际操作过程中,为了便于统一处理逻辑,尤其是应对要删除的节点可能是链表头节点这种特殊情况,我们通常会采用添加 “虚拟头节点” 的技巧来简化代码实现。

二、具体步骤与思路解析

(一)处理边界情况(空链表)

首先需要考虑一种特殊的边界情况,那就是当传入的链表本身就是空链表时(即 head 为 nullptr),这种情况下没有节点可供删除操作,直接返回原链表的头节点 head 就可以了,因为空链表无需做任何修改,保持原样返回就是正确的处理方式。

(二)添加虚拟头节点

为了让链表的删除操作逻辑更加简洁统一,我们创建一个新的节点作为虚拟头节点,例如:ListNode* dummy = new ListNode(-1);(这里给虚拟头节点赋的值 -1 只是一个示例,具体值不影响操作逻辑,只要便于区分就行),然后让这个虚拟头节点的 next 指针指向原来链表的头节点,即 dummy->next = head;

此时,我们后续的操作就可以从这个虚拟头节点开始遍历链表了,这么做的好处在于,当需要删除的节点恰好是原链表的头节点时,我们无需单独写额外的逻辑去处理头节点的删除情况,而是可以和删除其他普通节点一样,按照统一的逻辑进行处理,大大简化了代码的复杂度和逻辑判断。

(三)遍历链表并删除指定值的节点

接下来就是通过循环来遍历整个链表,以实现对每个节点值的检查以及相应的删除操作。常用的做法是使用一个指针(设为 cur),初始时让它指向我们创建的虚拟头节点,然后通过 while(cur->next) 这样的循环条件来进行循环,只要 cur 指针指向的当前节点的下一个节点存在(即 cur->next 不为 nullptr),就继续循环去检查后续的节点。

在循环体内部,我们需要对当前节点(也就是 cur 指针指向的节点)的下一个节点(通过 cur->next 访问)的值进行判断。如果发现 cur->next->val == val,这就意味着找到了一个需要删除的节点,此时我们通过改变指针的指向来实现节点删除,具体操作就是让 cur 指针的 next 指针跳过这个要删除的节点,直接指向它的下下个节点,即 cur->next = cur->next->next;,这样就相当于把值为 val 的这个节点从链表中移除掉了,实际是改变了链表的内部指针连接关系,使得该节点不再属于链表的一部分。

如果当前节点的下一个节点的值不等于 val,那就说明这个节点不需要被删除,此时我们只需要让 cur 指针往后移动一位,即 cur = cur->next;,继续去检查下一个节点的情况就可以了。

(四)返回处理后的链表头节点

经过前面的遍历和节点删除操作后,最后我们需要返回处理后的链表的头节点。由于之前添加了虚拟头节点,所以真正的链表头节点现在是由虚拟头节点的 next 指针指向的,因此我们直接返回 dummy->next 就可以得到经过处理后的链表的正确头节点了,这个头节点指向的链表就是已经删除了所有值为 val 的节点后的新链表。

三、总结

通过以上步骤,我们利用添加虚拟头节点的技巧,配合循环遍历和指针操作,统一且有条理地实现了删除链表中所有满足特定值节点的功能。这种思路在处理链表相关问题,尤其是涉及节点删除、插入等操作时经常会用到,希望大家通过对这道题思路的详细分析,能够更好地掌握链表操作的技巧,灵活应对类似的编程挑战呀


具体代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        if(!head)return head;
        ListNode* cur=new ListNode(-1);
        cur->next=head;
        ListNode* pre=cur;
        while(cur->next)
        {
            if(cur->next->val==val)cur->next=cur->next->next;
            else cur=cur->next;
        }return pre->next;
    }
};

在单链表操作中,常常会遇到依据特定值移除链表中节点的需求。下面这段 C++ 代码实现了给定一个单链表头节点指针 head 以及一个整数 val,将链表中所有值为 val 的节点移除的功能。

首先是边界情况处理,if(!head) return head; 这句代码考虑到了传入的链表为空(即 head 为 nullptr)的情况,此时无需操作,直接返回原 head 即可。

接着创建了一个虚拟头节点 ListNode* cur = new ListNode(-1);,并让其 next 指针指向真正的链表头节点 cur->next = head;,同时定义 ListNode* pre = cur;,这里的虚拟头节点作用很大,能统一后续移除节点的逻辑,避免对头节点单独判断。

核心的移除节点操作在 while(cur->next) 循环里,只要当前节点(cur 指向)的下一个节点存在就继续循环。循环体中通过 if - else 判断,若 cur->next->val == val,执行 cur->next = cur->next->next,即跳过值为 val 的节点,改变链表指针连接实现 “删除”;若不符合条件,则执行 cur = cur->next,继续检查下一个节点。

最后通过 return pre->next; 返回经过处理后的链表头节点,因为添加了虚拟头节点,真正的链表头就在 pre 的 next 指针指向处。总之,这段代码借助虚拟头节点,以清晰的逻辑和简洁的方式实现了单链表中指定值节点的移除功能,实用性很强哦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值