文章目录

题目概述

对应力扣​​203.移除链表元素​

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

链表系列① -- 移除链表元素_leetcode

解题思路

移除链表中的元素有两种方法:

  • 创建一个虚拟的头节点
  • 直接使用原来的链表来进行删除操作

这两种方法无论使用哪一种,都要借助双指针进行

方法一

创建一个虚拟头节点之后,将其next指向现在的head节点。设置快慢指针(我们规定pre表示快指针,cur表示慢指针),将pre指向虚拟头节点,将cur指向head节点。如果cur不为null就可以一直往后移动。在移动的途中比对cur中存储的数据是否符合删除的情况。

如果符合删除的情况,则将pre的next指向cur的next域,如此就相当于把cur指向的节点从这个链表中拆了下来。这之后一定要记得把cur向后移一位

链表系列① -- 移除链表元素_空指针_02

链表系列① -- 移除链表元素_java_03


如果不符合删除的情况,则直接将cur和pre指针向后移一位即可。

方法二

首先我们要单独讨论删除头节点的情况。操作也非常简单,将head向后移一位即可

链表系列① -- 移除链表元素_leetcode_04


链表系列① -- 移除链表元素_链表_05


然后其余的情况与方法一类似,创建两个指针pre,cur。pre指针指向head,cur指针指向head.next。具体的删除步骤与方法一相同。

代码实现

方法一

public ListNode removeElements1(ListNode head, int val) {
ListNode xuni = new ListNode(-1,head);
ListNode pre = xuni;
ListNode cur = xuni.next;
while(cur != null) {
if(cur.val == val) {
pre.next = cur.next;
}else {
pre = pre.next;
}
//不管是否删除了,都要将cur指针向后移一个
cur = cur.next;
}
return xuni.next;

方法二

public ListNode removeElements2(ListNode head, int val) {
//如果要删除头节点
while(head != null && head.val == val) head = head.next;
if(head == null) return head;
ListNode cur = head.next;
ListNode pre = head;
while(cur != null) {
if(cur.val == val) pre.next = cur.next;
else pre = pre.next;
cur = cur.next;
}
return head;
}

小总结

移除链表中的元素有两个需要注意的点:

注意点①:返回值

在方法二中直接return head无可厚非,但是在方法一中:

return xuni.next;

这个地方极易发生错误,容易错写成:

return

或者

return pre.next

那么这两个为什么不行呢?
return head不行是因为这个head节点可能已经被删除了,那么再返回它也就没有意义了。return pre.next不行是因为,此时你的pre指针已经到链表的末尾去了,你返回压根得不到什么东西。

注意点②:空指针

可以注意到我在方法二中多了这么一行代码:

if(head == null) return head;

这行代码在方法一中是没有的。这句话非常重要,并不是可有可无。
在方法二中如果给的是一个空链表,或者删除后成为了空列表,那么head就成为了一个空指针,而后面的head.next也就毫无意义了。方法一中不用加这句话是因为有一个虚拟头节点他是永远不会被删掉的,所以后面也就不会出现空指针报错的问题。