代码随想录day03:203.移除链表元素、707.设计链表、206.反转链表

203.移除链表元素

代码随想录讲解
自己的思路是直接在原来的链表上删除:
但是以下代码会报错(这段代码没考虑首节点为删除节点):Cannot read field “next” because “” is null
我的疑惑是,为什么先判断temp.next不为空,再将temp=temp.next,为什么会出现temp为空,从而引发空指针异常。
其实也很简单,
当temp.next是要被移除的节点时,代码执行了temp.next =temp.next.next。因为删除的是当前节点指向的节点,这会导致多越过一个节点,使当前节点成为被删除节点J的指向的节点K,从而判断K指向的节点,导致K节点被越过。
如果temp.next.next是null(即temp.next是链表的最后一个节点,并且这个节点被移除),那么temp.next会被设置为null。在下一个循环迭代中,当执行temp = temp.next时,temp也会变成null。然后在循环的开始尝试访问temp.next时,就会引发空指针异常。(根据写206题,不管逻辑上temp是否为空,直接判断temp.next就会报错,必须先判定temp是否为空)

  public static ListNode removeElements(ListNode head, int val) {
        ListNode temp=head;
        while(temp.next!=null){
            if(temp.next.val==val){
                temp.next=temp.next.next;
            }
            temp=temp.next;
        }
        return head;
    }

为了解决这个问题,可以在赋值temp = temp.next后加入一个检查,以确保temp不是null。下面是更新后的代码:

    public ListNode removeElements(ListNode head, int val) {
        //特殊情况处理:当整个链表为空
        if (head == null) {
            return null;
        }
        //移除头部需要被移除的节点
        while (head != null && head.val == val) {
            head = head.next;
        }
        ListNode temp=head;
        while(temp!=null&&temp.next!=null){
            if(temp.next.val==val){
                temp.next=temp.next.next;
                //不需要在这里移动temp,因为temp.next已经更新
            }else{
                //只有当不删除节点时才移动temp
                temp=temp.next;
            }
            
        }
        return head;
    }

链表操作的两种方式:
直接使用原来的链表来进行删除操作。
设置一个虚拟头结点在进行删除操作。

移除头结点和移除其他节点的操作是不一样的,因为链表的其他节点都是通过前一个节点来移除当前节点,而头结点没有前一个节点。
以一种统一的逻辑来移除 链表的节点:
可以设置一个虚拟头结点,这样原链表的所有节点就都可以按照统一的方式进行移除了。

public ListNode removeElements(ListNode head, int val) {
    if (head == null) {
        return head;
    }
    // 因为删除可能涉及到头节点,所以设置dummy节点,统一操作
    ListNode dummy = new ListNode(-1, head);
    ListNode pre = dummy;
    ListNode cur = head;
    while (cur != null) {
        if (cur.val == val) {
            pre.next = cur.next;
        } else {
            pre = cur;
        }
        cur = cur.next;
    }
    return dummy.next;
}

707.设计链表

这道题目设计链表的五个接口:
获取链表第index个节点的数值
在链表的最前面插入一个节点
在链表的最后面插入一个节点
在链表第index个节点前面插入一个节点
删除链表的第index个节点
下面设置一个虚拟头结点在进行操作。

//单链表
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 MyLinkedList {

    ListNode head;
    //初始化链表

    public MyLinkedList() {
        //虚拟头节点
        head=new ListNode();
    }
    //根据索引位置获取元素
    public int get(int index) {
        ListNode p=head;
        int i=-1;
        while(p!=null){
            if(i==index){
                return p.val;
            }
            p=p.next;
            i++;
        }
        return -1;
    }
    //在头部插入
    public void addAtHead(int val) {
        ListNode temp=new ListNode(val);
        temp.next=head.next;
        head.next=temp;
    }
    //在尾部插入
    public void addAtTail(int val) {
        ListNode temp=new ListNode(val);
        ListNode p=head;
        while(p.next!=null){
            p=p.next;
        }
        p.next=temp;
    }
    //根据索引位置插入
    public void addAtIndex(int index, int val) {
        ListNode temp=new ListNode(val);
        ListNode p=head;
        int i=0;
        while(p.next!=null){
            if(i==index){
                temp.next=p.next;
                p.next=temp;
                break;
            }
            p=p.next;
            i++;
        }
        //如果index等于链表长度,则直接插入尾部
        if(i==index){
            p.next=temp;
        }
    }
    //根据索引位置删除
    public void deleteAtIndex(int index) {
        ListNode p=head;
        int i=0;
        while(p.next!=null){
            if(i==index){
                p.next=p.next.next;
                break;
            }
            p=p.next;
            i++;
        }

    }
}

代码随想录讲解
在类中直接定义一个常量来记录链表长度,更加简洁。

206.反转链表

双指针法,用head保存了每次fast节点改变指向前的节点。
做了个动态图:
在这里插入图片描述

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode slow=head;
        ListNode fast=head;
        while(head!=null&&head.next!=null){
            fast=head.next;
            head.next=fast.next;
            fast.next=slow;
            slow=fast;
        }
        return fast;
    }
}
  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值