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

先手敲一遍ListNode 

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

1. 移除链表元素 

leetcode

视频讲解

这一题思路还是蛮简单的,我拿到这题的想法是:

一个指针(虚拟节点)直接指向当前节点,若它的下一个节点是要删的节点,则当前节点直接指向下下个节点,否则指针向后移动。

具体做法是:

1. 先考虑下head是不是null

        是null,直接返回null

        不是null,它的值是不是val,是val就将下一个节点当head,直到找到的head的值不是val

2. curr指针指向head,开始向后移动

3. 看curr和curr.next是否为null,是则结束

4. 看curr下一个节点的值是不是val

        是,当前节点直接指向下下个节点

        否,curr移动到下一个节点

        循环该步

5. 返回head

class Solution {
    public ListNode removeElements(ListNode head, int val) {
        // if (head == null) {
        //     return head;
        // }

        while(head != null && head.val == val) {
            head = head.next;
        }
        ListNode currNode = head;
        while(currNode != null && currNode.next != null){
            if(currNode.next.val == val){
                currNode.next = currNode.next.next;
            }else{
                currNode = currNode.next;
            }
        }
        return head;
    }
}

看了卡哥的讲解后学到了第二种解法,虚拟头节点

class Solution {
    public ListNode removeElements(ListNode head, int val) {
        ListNode dummyHead = new ListNode(0,head);

        ListNode currNode = dummyHead;
        while(currNode != null && currNode.next != null){
            if(currNode.next.val == val){
                currNode.next = currNode.next.next;
            }else{
                currNode = currNode.next;
            }
        }
        return dummyHead.next;
    }
}

这种写法个人感觉有两个要注意的点

1. dummyHead 要是new出来的,不能直接赋值

2. 返回的是dummyHead.next,原head有可能已经被删除

2.设计链表

leetcode

视频讲解

没什么好说的,一开始题都没看明白,直接看的讲解,然后自己写了一遍

class MyLinkedList {
    int size;
    ListNode dummyHead;

    public MyLinkedList() {
        size = 0;
        dummyHead = new ListNode(0);
    }
    
    public int get(int index) {
        if(index < 0 || index > size - 1){
            return -1;
        }
        ListNode curr = dummyHead;
        for(int i = 0; i <= index; i++){
            curr = curr.next;
        }
        return curr.val;
    }
    
    public void addAtHead(int val) {
        addAtIndex(0, val);
    }
    
    public void addAtTail(int val) {
        addAtIndex(size, val);
    }
    
    public void addAtIndex(int index, int val) {
        if(index < 0 || index > size){
            return;
        }

        ListNode curr = dummyHead;
        for(int i = 0; i < index; i++){
            curr = curr.next;
        }
        curr.next = new ListNode(val, curr.next);
        // ListNode temp = new ListNode(val);
        // temp.next = curr.next;
        // curr.next = temp;
        size++;
    }
    
    public void deleteAtIndex(int index) {
        if(index < 0 || index >= size){
            return;
        }

        ListNode curr = dummyHead;
        for(int i = 0; i < index; i++){
            curr = curr.next;
        }
        curr.next = curr.next.next; 
        size--;
    }
}

不管是增还是删,都是对目标节点的前一个节点进行操作,也就是说curr指针指到 index-1 的位置就行了。

3. 反转链表 

leetcode

视频讲解

这题之前在别的地方看过,也比较简单,琢磨一会也就做出来了

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode pre = null;
        ListNode curr = head;
        ListNode temp = null;
        while(curr != null){
            temp = curr.next;
            curr.next = pre;
            pre = curr;
            curr = temp;
        }
        return pre;
    }
}

核心思想就是定义双指针

pre初始值为null,可以看成是在head前加了一个空头,curr从head开始

然后在curr指向pre前,把后一个节点存在temp中

接着双指针都向后移动,pre到curr的位置,curr到temp的位置。

最后curr为null时,说明已经走完,而此时pre的位置就是新头了。

看了视频之后,学习到了递归写法(以前没怎么接触过递归,在理解双指针写法的情况下,还是很容易理解的

class Solution {
    public ListNode reverseList(ListNode head) {
        return reverse(null, head);
    }

    public ListNode reverse(ListNode pre, ListNode curr){
        if(curr == null){
            return pre;
        }
        ListNode temp = curr.next;
        curr.next = pre;
        return reverse(curr, temp);
    }
}

reverse函数的结束条件自然是前面循环结束的条件,curr为null时,返回pre

初始是将null和head反转,相当于将head变为tail

反转的方法还是一样的,要准备一个temp

后面的递归,就是将pre和curr后移后指向的元素的反转,即将curr和temp递归

你可能感兴趣的:(算法,链表,java)