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

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

  • 链表基础
  • 203.移除链表元素
    • 解法一:直接删除(区分头节点和中间节点)
    • 解法二:虚拟头节点
  • 707.设计链表
    • 解法一:不使用虚拟头节点(输出有误,还没改)
    • 解法二:虚拟头节点
  • 206.反转链表
    • 解法一:双指针
    • 解法二:递归
  • 总结


链表基础

代码随想录算法训练营day03 | 203.移除链表元素,707.设计链表,206.反转链表_第1张图片

定义单向链表:

class ListNode{
	// 下一节点和当前节点值
    ListNode next;
    int value;
    // 三种构造函数
    public ListNode(){}
    
    public ListNode(int val){
        this.value = val;
    }
    
    public ListNode(int val,ListNode next){
        this.value = val;
        this.next = next;
    }
}

代码随想录算法训练营day03 | 203.移除链表元素,707.设计链表,206.反转链表_第2张图片


203.移除链表元素

教程视频:https://www.bilibili.com/video/BV18B4y1s7R9/?vd_source=ddffd51aa532d23e6feac69924e20891
代码随想录算法训练营day03 | 203.移除链表元素,707.设计链表,206.反转链表_第3张图片
代码随想录算法训练营day03 | 203.移除链表元素,707.设计链表,206.反转链表_第4张图片

解法一:直接删除(区分头节点和中间节点)

链表中删除头节点操作和中间节点的操作不同。
因此本题要先确定新的头节点,之后再遍历删除中间节点。
头节点删除是将head后移,中间节点是将 next 指向 next.next 。
注意: 单向链表不能找前一节点,因此循环判定条件是下一节点不为空。

    public ListNode removeElements(ListNode head, int val) {
        //确定新的头节点
        while(head!=null && head.val==val){
            head=head.next;
        }
        // 设置虚拟指针 currentNode
        ListNode currentNode = head;
        while(currentNode!=null && currentNode.next!=null){
            if(currentNode.next.val==val){
                //删除currentNode.next
                currentNode.next=currentNode.next.next;
            }else{
                currentNode=currentNode.next;
            } 
        }
        return head;
    }

解法二:虚拟头节点

加入虚拟头节点,能够统一对单向链表头节点和中间节点的增删操作,使代码更简洁。

    public ListNode removeElements(ListNode head, int val) {
        // 创建虚拟头节点,让其位于head前
        ListNode dummyhead = new ListNode();
        dummyhead.next = head;

        //指针
        ListNode curr = dummyhead;

        //遍历删除无用节点
        while(curr.next!=null){
            if(curr.next.val==val){
                curr.next = curr.next.next;
            }else{
                curr = curr.next;
            }
        }
        return dummyhead.next;
    }

707.设计链表

教程视频:https://www.bilibili.com/video/BV1FU4y1X7WD/?vd_source=ddffd51aa532d23e6feac69924e20891
代码随想录算法训练营day03 | 203.移除链表元素,707.设计链表,206.反转链表_第5张图片代码随想录算法训练营day03 | 203.移除链表元素,707.设计链表,206.反转链表_第6张图片

解法一:不使用虚拟头节点(输出有误,还没改)

class MyLinkedList {
    int val;
    MyLinkedList next;

    public MyLinkedList() {

    }
    
    public int get(int index) {
        int num = 0;
        while(this!=null){
            if(num==index){
                return this.val;
            }else if(this.next!=null){
                this = this.next;
                num++;
            }
        }
        return -1;
    }
    
    public void addAtHead(int val) {
        MyLinkedList head = new MyLinkedList();
        head.val = val;
        head.next = this;
    }
    
    public void addAtTail(int val) {
        MyLinkedList newNode = new MyLinkedList();
        head.val = val;
        if(this==null){
            this = newNode;
            return;
        }
        while(this.next!=null){
            this = this.next;
        }
        this.next = newNode;
    }
    
    public void addAtIndex(int index, int val) {
        MyLinkedList node =  new MyLinkedList();
        node.val = val;

        int num = 0;
        while(this!=null){
            if(num==index){
                node.next = this.next;
                this.next = node;
            }else if(this.next!=null){
                this = this.next;
                num++;
            }
        }
        
    }
    
    public void deleteAtIndex(int index) {
        // 删除头节点
        if(index==0){
            this = this.next;
        }
        // 删除中间节点
        int num = 1;
        while(this.next!=null){
            if(num==index){
                this.next = this.next.next;
            }
        }
    }
}

解法二:虚拟头节点

class ListNode {
    int val;
    ListNode  next;
    
    public ListNode (){}
    public ListNode (int value){
        this.val = value;
    }
}

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

    public MyLinkedList() {
        size = 0;
        head = new ListNode  ();
    }
    
    //获取第index个节点的数值,注意index是从0开始的,第0个节点就是头结点
    public int get(int index) {
        //判断index有效
        if(index<0 || index>size-1){
            return -1;
        }
        //遍历链表
        ListNode currentNode = head.next;//指针
        while(index>0){ //带入index=0 来确定判断条件
            currentNode = currentNode.next;
            index--;
        }
        return currentNode.val;
    }
    
    public void addAtHead(int val) {
        addAtIndex(0,val);
        // ListNode  newHead = new ListNode (val);
        // newHead.next = head.next;
        // head.next = newHead;
        // size+=1;
    }
    
    public void addAtTail(int val) {
        addAtIndex(size,val);
        // ListNode  newTail = new ListNode (val);
        // ListNode  currentNode = head;
        // while(currentNode.next!=null){
        //     currentNode = currentNode.next;
        // }
        // currentNode.next = newTail;
        // size+=1;
       
    }
    
    public void addAtIndex(int index, int val) {
        //判断index有效
        if(index<0 || index>size){ //这里index等于size的情况也可插入节点
            return;
        }

        //创建要插入的结点
        ListNode  newNode =  new ListNode (val);

        //遍历指针
        ListNode  currentNode = head;
        while(index>0){
            currentNode = currentNode.next;
            index--;
        }
        newNode.next = currentNode.next;
        currentNode.next = newNode;
        size+=1;
    }
    
    public void deleteAtIndex(int index) {
        //判断index有效
        if(index<0 || index>size-1){
            return;
        }
        //指针
        ListNode  currentNode = head;
        while(index>0){
            currentNode = currentNode.next;
            index--;
        }
        currentNode.next = currentNode.next.next;
        size-=1;
    }
}

206.反转链表

教程视频:https://www.bilibili.com/video/BV1nB4y1i7eL/?spm_id_from=333.788&vd_source=ddffd51aa532d23e6feac69924e20891
代码随想录算法训练营day03 | 203.移除链表元素,707.设计链表,206.反转链表_第7张图片
代码随想录算法训练营day03 | 203.移除链表元素,707.设计链表,206.反转链表_第8张图片
进阶:链表可以选用迭代或递归方式完成反转。你能否用两种方法解决这道题?

解法一:双指针

    public ListNode reverseList(ListNode head) {
        //快慢指针
        ListNode currentNode = new ListNode();
        currentNode = head;
        ListNode preNode = null;

        while(currentNode!=null){
            ListNode TempNode = new ListNode();
            TempNode = currentNode.next;
            currentNode.next = preNode;
            preNode = currentNode;
            currentNode = TempNode;
        }
        return preNode;
    }

解法二:递归

    public ListNode reverse(ListNode cur, ListNode pre){
        if(cur==null){return pre;}
        ListNode temp = new ListNode();
        temp = cur.next;
        cur.next = pre;
        // pre = cur;
        // cur = temp;
        return reverse(temp, cur);//调用递归完成上两行的交换
    }
    
    public ListNode reverseList(ListNode head) {
        return reverse(head, null);
    }

总结

1、虚拟头节点可以将单向链表的操作统一起来,减少由于头节点操作不一致导致的分类讨论;
2、单向链表操作时一定要考虑清楚,当前指针需要指向哪个节点;
3、反转链表直接将链表next指向修改即可,不需要多次遍历链表。

你可能感兴趣的:(代码随想录训练营,链表,算法,数据结构)