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

58 阅读4分钟

203. 移除链表元素

题目链接

解题方法: 虚拟头节点

图示(来源:代码随想录)

20210316095619221.png

删除节点需要考虑两种情况:

  1. 删除头节点

  2. 删除非头节点

使用虚拟头节点的好处:可以针对不同情况以同一个规则进行删除/增加节点

具体解题步骤:

  1. 定义一个虚拟头节点(dummyHead
  2. 让虚拟头节点的 next 节点指向链表的头节点
  3. 在虚拟头节点处定义一个指针 cur 用来遍历链表
  4. 遍历链表,判断 cur.next.val 是否等于需要删除的目标值(target
    • 相等,就让 cur 指针的 next 指向 cur 指针的 nextnext,从而删除节点
    • 不等,则继续遍历链表
  5. 最后返回新的头节点为虚拟头节点的 next 节点

解题代码:

/**
 * Definition for singly-linked list.
 * 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; }
 * }
 */
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        //定义虚拟头节点并指定val和next节点
        ListNode dummyHead = new ListNode(-1,head);
        //dummyHead.next = head;
        ListNode cur = dummyHead; //定义cur指针遍历链表
        while(cur.next != null){
            if(cur.next.val == val){
                cur.next = cur.next.next;
            }else{
                //如果不是要删除的目标值,就继续遍历
                cur = cur.next;
            }
            
        }
        //最后返回的是虚拟头节点的next节点
        return dummyHead.next;
    }
}

707. 设计链表

题目链接

解题方法:虚拟头节点、链表基础知识

个人感想:以前自己没有设计过链表,听完视频讲解后自己尝试写代码还是有点吃力,思想懂了但是代码实现的过程中还是出现各种问题,就把代码拉到idea中编写边思考调试(**建议多刷几遍 :) **)

解题代码:

//要会自己写
public class ListNode {
    int val;
    ListNode next;
    ListNode() {}
    ListNode(int val) {
        this.val = val;
    }
}

class MyLinkedList {
    //链表长度
    int size;
    //虚拟头节点
    ListNode dummyHead;

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

    /**
     * 获取链表中下标为 index 的节点的值,如果下标无效,则返回 -1
     */
    public int get(int index) {
        if (index < 0 || index >= size) {
            return -1;
        }
        //这里我和题解的不太一样,我是把 cur 设置成 dummyHead.next
        // 所以下面的循环中 i < index 没有 =
        ListNode cur = dummyHead.next;
        for (int i = 0; i < index; i++) {
            cur = cur.next;
        }
        return cur.val;
    }

    /**
     * 将一个值为 val 的节点插入到链表中第一个元素之前,在插入完成后,新节点会成为链表的第一个节点
     */
    public void addAtHead(int val) {
        addAtIndex(0, val);
    }

    /**
     * 将一个值为 val 的节点追加到链表中作为链表的最后一个元素
     */
    public void addAtTail(int val) {
        addAtIndex(size, val);
    }

    // 在第 index 个节点之前插入一个新节点,例如index为0,那么新插入的节点为链表的新头节点。
    // 如果 index 等于链表的长度,则说明是新插入的节点为链表的尾结点
    // 如果 index 大于链表的长度,则返回空
    public void addAtIndex(int index, int val) {
        if (index > size) {
            return;
        }
        if (index < 0) {
            index = 0;
        }
        size++;
        ListNode newNode = new ListNode(val);
        ListNode cur = dummyHead;
        for (int i = 0; i < index; i++) {
            cur = cur.next;
        }
        newNode.next = cur.next;
        cur.next = newNode;
    }
	//如果下标有效,则删除链表中下标为 index 的节点
    public void deleteAtIndex(int index) {
        if (index < 0 || index >= size) {
            return;
        }
        size--;
        ListNode cur = dummyHead;
        for (int i = 0; i < index; i++) {
            cur = cur.next;
        }
        cur.next = cur.next.next;
    }
}

温馨提醒:

  1. 要操作一个节点,一定需要确定它前面的一个节点 ( 非常重要!!!)
  2. 增加和删除后,要更新链表的size(注:自己写的时候就没注意,导致空指针异常,找了好久的错。。。)

206. 反转链表

题目链接

解题思路:双指针/递归两种思路

实现前后效果:

20210218090901207-1695445750999-3.png

实现动态图:

206.翻转链表.gif

双指针实现步骤(重点):

  1. 定义一个 cur 指针,指向头结点,再定义一个 pre 指针,初始化为 null
  2. 定义一个 temp 指针,指向 cur.next ,目的是保存接下来cur指针的指向。
  3. 循环链表,移动 precur 指针,直到 cur 指针指向为 null 时返回新的头节点 pre

递归实现:递归实现的代码是根据双指针实现

注意!!!:递归中的传递参数到底填什么

解题代码:

双指针思路

/**
 * Definition for singly-linked list.
 * 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; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode cur = head;
        ListNode pre = null;
        while(cur != null){
            ListNode temp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = temp;
        }
        return pre;
    }
}

递归思路

/**
 * Definition for singly-linked list.
 * 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; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
       return reverse(head,null);
    }

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