题目链接:力扣

力扣刷题——————>单链表系列

第一种解法:在原链表上进行操作,小红日烧脑版


/*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val = val; }* ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/class Solution{public ListNode removeElements(ListNode head, int val){if(head== null)  return head;ListNode cur=head;ListNode ahead=null;while(cur != null){if(cur.next != null)//首先当前的下一个不为空{ahead = cur.next;//调用先驱节点往前走,此句话保证了ahead一直在cur后面一位,紧跟着新curif(ahead.val == val)//如果先驱节点的值正好等于目标值{cur.next=ahead.next;//跨过ahead节点连接ahead = cur;//先驱节点退回,等待下一次使用。}}if(cur.next != null && cur.next.val != val){cur = cur.next;//cur能向前移动ahead = ahead.next;}if(cur.next == null){if(head.val == val) return head.next;else break;}}return head;}}

关于本题解,补充说明如下,

//首先其实本题我的解法循环不变量设置的有问题,很多情况下不论是数组还是链表
//快慢指针也好,滑动窗口也罢,其实极大多数都是将走的快的指针 一探到底设置为终止条件的

//循环不变量设置为cur,我的上述都是在while循环内针对cur.next不为空进行的操作,也就是最后cur.next==null的时候循环出不去了,所以需要进行处理!

//只有cur的下一个节点的值不为目标值,才能移动cur,所以到了此步(cur.next==null),不用再检查cur的val了

//拐回去判断一下头节点即可!~~因为一开始就是从cur和cur.next起始的,正好错过第一个头结点记得要在内部返回,不然报错死循环!也就是说你循环不变量找错了,需要手动退出~太菜了
//所以推荐大家用移动的快的指针做循环不变量终止循环!

根据本题,总结经验:

1:从一开始如果第一个头结点后是一连串符合要求需要删去的,那么要求你要么不断将指针回退,避免连续符合要求的情况,但是指针不断前进漏过去了:

要么跳过第一个头结点,扫描一遍再回头看第二个

2:while循环还是要找对循环不变量条件,出去的条件要考虑到

很多情况下不论是数组还是链表
//快慢指针也好,滑动窗口也罢,其实极大多数都是将走的快的指针 一探到底设置为终止条件的

找对条件事半功倍

3: 其次,如果起手一连串相同的,不如先考虑从第二个开始,然后再回头检查第一个,这种思想真的不错。


力扣刷题——————>单链表系列

第一题:移除链表元素


第二种解法:在原链表上进行操作,博哥版

此题某种意义上可以写成 单链表内的增删查改中的删除方法,remove属实高效。

更改了循环不变量!

/*** Definition for singly-linked list.* <p>* public class ListNode {* <p>* int val;* <p>* ListNode next;* <p>* ListNode() {}* <p>* ListNode(int val) { this.val = val; }* <p>* ListNode(int val, ListNode next) { this.val = val; this.next = next; }* <p>* }*/class Solution {//博哥解法public ListNode removeElements(ListNode head, int val) {if (head == null) return head;//只有在此判断是不是链表上来就为空,反手一个空,下面的引用变量就爆炸了,无法声明ListNode cur = head;//起手把用来穿的固定节点定在第一个ListNode ahead = head.next;//把先驱节点定在第二个//到时候回头来检查第一个节点//如果是 66666 val==6这种极端特判,从第一个开始检查太费劲,先驱结点需要不断退回~while (ahead != null)//此处用ahead先驱节点做循环不变量,好处有三//1:下面循环内的两种情况,不管何种,ahead的位置都在不断变更向前,当ahead为空,链表扫描一遍,复杂度为n//2:如果是只有一个节点的情况,ahead就是空,进不去循环。{if (ahead.val == val)//如果先驱节点的值就是目标值,先跳过这个结点,然后再跟固定的穿起来{ahead = ahead.next;cur.next = ahead;} else//先驱节点安全,先往前再说,新ahead的值下次循环再判{cur = cur.next;ahead = ahead.next;}}//出了循环,然后再判断头结点if (head.val == val) {return head.next;}return head;}}

第三种解法:论 链表的暴力解法!及其容易出现和发生的bug