代码随想录算法训练营第3天 | 203.移除链表元素、707.设计链表、206.反转链表

目录

203.移除链表元素

1.解题思路

2.遇到的问题

3.实现代码

4.题目总结

707.设计链表

代码实现

206.反转链表

代码实现


203.移除链表元素

题目链接:203.移除链表元素

1.解题思路

链表中的删除是跳过那个值

普通方法:(不用虚拟头节点)

要把满足val的节点的前一个链表中指向下一个的引用改变为val中的引用,但如果是头节点就没有前一个,所以首先判断元素是否为头节点。定义一个临时cur不直接操作head是因为要返回head。

虚拟头节点:

虚设一个头节点ListNode dummy = new ListNode(),这个头节点的next指向head,cur指向dummy,cur在else出才改变他的指向,在此之前cur一直指向dummy指向的实例及现在cur.next改变dummy.next也会改变,直到cur.next.val != val,然后此时cur.next改变dummy.next不会改变。

这里不返回head是因为head可能被删除了(跳过了)。

2.遇到的问题

1.在用普通方法时,判断进入循环条件一直不理解为什么还要判断cur.next!=null,以为无法判断最后一个val的值,虽然指针指着倒数第二个,最后一个不能进入循环,但cur.next.val==val判断了最后一个ListNode的val。

2.不清楚什么cur的指向,在解题思路中已经给出。

3.实现代码

普通方法

 public ListNode removeElements(ListNode head, int val) {
        while (head!=null&&head.val==val){//这里使用while是防止下一个head的val也是val
            head=head.next;
        }
        ListNode cur=head;
        while (cur!=null&&cur.next!=null){//因为是判断cur.next.val的值所以指针停在倒数第二个就行了,因为cur.next.val已经判断了下一个的val
            if (cur.next.val==val){
                cur.next=cur.next.next;
            }else {
                cur=cur.next;
            }
        }
        return head;

    }

虚拟头节点:

public ListNode removeElements(ListNode head, int val) {
        // 设置一个虚拟的头结点
        ListNode dummy = new ListNode();
        dummy.next = head;

        ListNode cur = dummy;
        while (cur.next != null) {
            if (cur.next.val == val) {
                cur.next = cur.next.next;
            } else {
                cur = cur.next;//这里才改变cur的指向
            }
        }
        return dummy.next;
    }
4.题目总结

虚拟头节点法可以有效地从列表中删除具有指定值的所有节点,同时借助虚拟节点优雅地处理边缘情况,及可以统一处理边缘的方法。

707.设计链表

题目链接:设计链表

代码实现

在代码注释里面包含了解释,思路,重点

在增加,删除操作时,一定要知道前一个的数据,注意遍历方法,将虚拟head看成最前面的节点,NULL看成最后一个节点,增加删除可以用同一种方法遍历,与增加。

单链表:

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;
    }

}



public class MyLinkedList {
    //size储存链表元素个数
    int size;
    //虚拟头节点
    ListNode head;

    //初始化链表
    public MyLinkedList(){
        size=0;
        head=new ListNode(0);
    }



    //获取链表下标为index的节点的值,如果无效返回-1
    public int get(int index) {
        if (index<0||index>=size){
            return -1;
        }
        ListNode cur=head;//cur指向下标为-1的位置
        while (index>0){//用cur来遍历链表,cur遍历到index-1位置
            cur=cur.next;
            index--;
        }
        return cur.next.val;

    }


    //将一个值为val的节点插入到链表的第一个节点
    // 新节点会成为链表的第一个节点
    public void addAtHead(int val) {
        ListNode newNode=new ListNode(val);
        //先是指向后面,因为head.next后面要边
        // 如果是第一个,相当于在head,NULL之间加一个节点
        newNode.next=head.next;
        head.next=newNode;
        size++;

    }


    //将一个值追加到链表中作为链表最后一个元素
    public void addAtTail(int val) {

        ListNode newNode=new ListNode(val);
        ListNode cur=head;
        int n=size;
        while (n>0){//遍历到最后一个下标位置,及size-1
            cur=cur.next;
            n--;
        }
        newNode.next=cur.next;
        cur.next=newNode;
        size++;

    }


    //将一个val值为val的节点插入到1链表中下标为index的节点之前
    //如果index的等于链表长度,那么就追加到末尾
    //大于size则不会插入链表
    public void addAtIndex(int index, int val) {
        if (index>size){
            return;
        }
        if (index<0){
            index=0;
        }
        ListNode newNode=new ListNode(val);
        ListNode cur=head;
        while (index>0){//cur遍历到index-1位置
            cur=cur.next;
            index--;

        }
        newNode.next=cur.next;
        cur.next=newNode;
        size++;

    }

    public void deleteAtIndex(int index) {
        if (index<0||index>=size){
            return;
        }
        ListNode cur=head;
        while (index>0){//cur遍历到index的前一个
            cur=cur.next;
            index--;
        }
        cur.next=cur.next.next;
        size--;

    }



}

206.反转链表

题目链接:反转链表

代码实现

双指针:

//双指针方法
    public ListNode reverseList(ListNode head) {//传一个链表的头节点进来

        ListNode pre=null;//定义一个前置虚拟头节点
        ListNode cur=head;
        while (cur!=null){//直到cur==null时停止遍历
            //用来临时储存cur的下一个,因为后面cur的下一个会改变,变为指向pre
            ListNode temp=cur.next;
            //pre要变为改变后的cur,然后cur指向下一个
            cur.next=pre;
            pre=cur;
            cur=temp;

        }
        //最后cur指向null,pre指向最后一个节点
        return pre;
    }

递归:

 //递归解法
    public static ListNode reverse(ListNode cur,ListNode pre){
        if (cur==null){
            return pre;
        }
        ListNode temp=cur.next;
        cur.next=pre;
        return reverse(temp,cur);
    }
    public ListNode reverseList(ListNode head){
        return reverse(head,null);
    }

  • 8
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值