题目来自力扣官网: https://leetcode-cn.com/problems/remove-linked-list-elements/

删除链表中等于给定值 val 的所有节点。

示例:

输入: 1->2->6->3->4->5->6, val = 6

输出: 1->2->3->4->5

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode removeElements(ListNode head, int val) {
 
    }
}

链表一直理解的不好,没有什么好的方法,硬着头皮写:

肯定是从head开始遍历,判断当前节点n是不是==val,如果等于,就跳过n,让n的前一个节点指向n的后一个节点。

但是如果n是head的时候,没有前一个节点,可以造一个链表头pre指向head,最终返回pre.next。

从pre开始遍历,每次判断当前节点的下一个节点是不是==val,等于就跳过当前节点,不等于就向后移动pre。

为什么需要一个游标呢?一开始我没有想到可以用游标,就是直接操作pre,但是最终是要返回pre.next,

要是pre往后移动了,就没法返回了。返回head也是不行的,有可能pre不指向head了已经,可能跳过了head!所以,搞一个游标(还是应该叫做指针?我理解其实就是一个变量,把pre节点赋值给变量),

然后操作这个游标,pre节点还是在那里没动。

代码如下:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        //记得写边界条件
        if(head==null){
            return null;
        }
        //这一段用不用写?
        if(head.next==null){
            if(head.val==val){
                return null;
            }else{
                return head;
            }
        }
        ListNode pre=new ListNode(0);
        pre.next=head;
        ListNode p=pre;
        while(p.next!=null){
            if(p.next.val==val){
                //跳过一个
                p.next=p.next.next;
            }else{
                //移动游标p
                p=p.next;
            }
        }
        return pre.next;
    }
}

再上一个第一次写的代码吧:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        if(head==null){
            return null;
        }
        if(head.next==null){
            if(head.val==val){
                return null;
            }else{
                return head;
            }
        }
        //逻辑是什么:需不需要拼一个链表头?
        //假如不拼,判断当前节点是否为空,但是如果head=val怎么办
        ListNode n=new ListNode(0);
        n.next=head;
        //这儿为什么不报错?为什么可以这么写?————这是把n这个节点给了pre,那么pre是一个节点?还是一个游标?
        ListNode pre=n;
        //ListNode cur=n.next;
        //循环
        while(pre.next!=null){
            if(pre.next.val==val){
                if(pre.next.next!=null){
                    pre.next=pre.next.next;
                }else{
                    pre.next=null;
                }
            }else{
                //这个是把pre往后移动了,还是修改了指针————节点间的指针没有动,但是pre是下一个节点了,是移动游标的操作。
                pre=pre.next;
            }
        }
        //这里返回head也不对(可能n不指向head了,返回head就不对了),返回n.next也不对(n.next可能不是head了)
        //重要的是要改变head的指针,而且必须返回head这个节点————再搞一个游标pre,然后每次都操作pre。这样n.next就没变,就是head
        return n.next;
    }
}

实际应该是比较简单的一个问题,这道题做完了以后终于有点理解链表的操作了。再遇到链表的题目可以先把思路想清楚,然后就是写!像是一个把思路翻译成代码的过程,所以必须要熟练。