给你一个链表的头节点 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
首先,我们看到此题的第一反应一定是要循环遍历该链表,并在循环时对链表进行一些操作。
循环遍历操作:
- ListNode cur=head;
- //循环遍历
- while(cur!=null){
- cur=cur.next;
- }

其次,应该在循环遍历的基础上进行特定结点的删除工作,当结点元素的值(cur.val)和传入值(val)相等时,删除该结点。
比如上图,如果我们想删除 "6" 这个结点元素,让 "2" 直接指向 "3" ,从而实现删除 "6" 的操作,此时使要删除的结点(cur)为 "6" ,那么我们就需要一个结点来记录要删除结点(cur)的前驱结点(prev),从而使该结点(cur)的前驱结点(prev)直接指向该结点(cur)的后续结点(cur.next)。
需要注意的是,需要删除cur时,prev不应该往后移动,因为删除后,下一个结点的前驱结点仍是该prev。
- ListNode prev=null; //记录前驱结点 这种方式是错误的,后面会讲到
- while(cur!=null){
- if(cur.val==val){
- prev.next=cur.next;
- }else{
- prev=cur;
- }
- cur=cur.next;
- }

这时我们需要思考一个问题,如果头结点(head)是我们需要删除的元素,这样写还成立吗?
答案是不成立的。原因在于,prev=null,如果使prev.next=cur.next,此时cur=head,这是两个解引用的操作,那么由于prev=null,对其进行解引用就会造成空指针异常,有以下两种解决方法:
第一种就是分情况讨论,当cur==head时,返回head.next,作为新的头结点;
第二种也就是如下这种方式,是先创建一个工具结点(fakeHead)指向head,使prev=fakeHead,也就是在头结点前面新创建了一个结点(fakeHead),这样就可以不用分情况讨论,最后返回fakeHead.next即可。
- ListNode fakeHead=new ListNode();
- fakeHead.next=head;
- ListNode prev=fakeHead; //构造一个假结点
- class Solution {
- public ListNode removeElements(ListNode head, int val) {
- ListNode cur=head;
- ListNode fakeHead=new ListNode();
- fakeHead.next=head;
- ListNode prev=fakeHead; //构造一个假结点
- while(cur!=null){
- if(cur.val==val){
- prev.next=cur.next;
- }else{
- prev=cur;
- }
- cur=cur.next;
- }
- return fakeHead.next;
- }
- }

如想了解链表(LinkedList)相关知识,请查阅:
如有建议或想法,欢迎一起讨论学习~