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


    JAVA代码编写

    203. 移除链表元素

    给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点

    示例 1:

    img

    输入:head = [1,2,6,3,4,5,6], val = 6
    输出:[1,2,3,4,5]
    
    • 1
    • 2

    示例 2:

    输入:head = [], val = 1
    输出:[]
    
    • 1
    • 2

    示例 3:

    输入:head = [7,7,7,7], val = 7
    输出:[]
    
    • 1
    • 2

    提示:

    • 列表中的节点数目在范围 [0, 104]
    • 1 <= Node.val <= 50
    • 0 <= val <= 50

    教程:https://programmercarl.com/0203.%E7%A7%BB%E9%99%A4%E9%93%BE%E8%A1%A8%E5%85%83%E7%B4%A0.html

    视频:https://www.bilibili.com/video/BV18B4y1s7R9

    方法一:设置一个虚拟头结点

    思路:首先为什么要加虚拟头结点,是因为如果要删的元素是头结点,会与删后面的结点操作不一样,这样比较方便。定义一个当前指针cur用来变量,定义一个pre指针,用来删除结点,经典的指针删除的操作如下图所示,将pre指向cur。这里要注意的是,当不是要删除的元素时,pre指针需要往后移一位。还有while循环需要注意,虽然看代码能懂,写起来还是有点磕磕绊绊。

    203_链表删除元素1

    复杂度分析

    • 时间复杂度: O ( n ) O(n) O(n)
    • 空间复杂度: O ( 1 ) O(1) O(1)
    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) {
    
            if (head==null){//如果头结点head为空
                return head;//直接返回head,不需要删除操作
            }
    
            ListNode dummy=new ListNode(-1,head);//定义一个指针,值为-1,在head前一个
            ListNode pre = dummy;//当前指针的前一个指针
            ListNode cur = head;//当前指针
    
            while(cur!=null){//当前指针不为空
                if (cur.val==val){//指针值是目标值
                    pre.next=cur.next;//前一个指针直接指向下下个指针,跳过指定目标值
                }else {
                    pre = cur;//如果不是要删除的指针,就和cur一样,往后移一位,以便下一次删除操作
                }
                cur=cur.next;
    
            }
            return dummy.next;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    看一个例子,输入:head = [1,2,6,3,4,5,6], 要删元素6。
    在这里插入图片描述

    class Solution {
        public ListNode removeElements(ListNode head, int val) {
            ListNode dummyHead = new ListNode(0);
            dummyHead.next = head;//在head之前定义一个dummyHead结点,其值为0
            ListNode temp = dummyHead;
            while (temp.next != null) {
                if (temp.next.val == val) {
                    temp.next = temp.next.next;
                } else {
                    temp = temp.next;
                }
            }
            return dummyHead.next;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    这个代码是leetcode官方提供的,与卡哥的代码差不多,这里少定义了一个指针cur,因为cur=temp.next,这里都用temp代劳了。

    707. 设计链表

    企业:谷歌、亚马逊、字节

    你可以选择使用单链表或者双链表,设计并实现自己的链表。

    单链表中的节点应该具备两个属性:valnextval 是当前节点的值,next 是指向下一个节点的指针/引用。

    如果是双向链表,则还需要属性 prev 以指示链表中的上一个节点。假设链表中的所有节点下标从 0 开始。

    实现 MyLinkedList 类:

    • MyLinkedList() 初始化 MyLinkedList 对象。
    • int get(int index) 获取链表中下标为 index 的节点的值。如果下标无效,则返回 -1
    • void addAtHead(int val) 将一个值为 val 的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表的第一个节点。
    • void addAtTail(int val) 将一个值为 val 的节点追加到链表中作为链表的最后一个元素。
    • void addAtIndex(int index, int val) 将一个值为 val 的节点插入到链表中下标为 index 的节点之前。如果 index 等于链表的长度,那么该节点会被追加到链表的末尾。如果 index 比长度更大,该节点将 不会插入 到链表中。
    • void deleteAtIndex(int index) 如果下标有效,则删除链表中下标为 index 的节点。

    示例:

    输入
    ["MyLinkedList", "addAtHead", "addAtTail", "addAtIndex", "get", "deleteAtIndex", "get"]
    [[], [1], [3], [1, 2], [1], [1], [1]]
    输出
    [null, null, null, null, 2, null, 3]
    
    解释
    MyLinkedList myLinkedList = new MyLinkedList();
    myLinkedList.addAtHead(1);
    myLinkedList.addAtTail(3);
    myLinkedList.addAtIndex(1, 2);    // 链表变为 1->2->3
    myLinkedList.get(1);              // 返回 2
    myLinkedList.deleteAtIndex(1);    // 现在,链表变为 1->3
    myLinkedList.get(1);              // 返回 3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    提示:

    • 0 <= index, val <= 1000
    • 请不要使用内置的 LinkedList 库。
    • 调用 getaddAtHeadaddAtTailaddAtIndexdeleteAtIndex 的次数不超过 2000

    教程:https://programmercarl.com/0707.%E8%AE%BE%E8%AE%A1%E9%93%BE%E8%A1%A8.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE

    视频:https://www.bilibili.com/video/BV1FU4y1X7WD

    方法一:单链表

    思路

    复杂度分析

    • 时间复杂度: 涉及 index 的相关操作为 O(index), 其余为 O(1)

    • 空间复杂度: O(n)

    class ListNode {//定义指针结点类
        int val;
        ListNode next;
        ListNode(){}
        ListNode(int val) {
            this.val=val;
        }
    }
    class MyLinkedList {
        //size存储链表元素的个数
        int size;
        //虚拟头结点
        ListNode head;
    
        //初始化链表:size为0,但是有虚拟头结点值为0
        public MyLinkedList() {
            size = 0;//包含ListNode个数
            head = new ListNode(0);
        }
    
        //获取第index个节点的数值,注意index是从0开始的,第0个节点就是头结点
        public int get(int index) {
            //如果index非法,返回-1
            if (index < 0 || index >= size) {//index合理范围是[0,size-1]
                return -1;
            }
            ListNode currentNode = head;
            //包含一个虚拟头节点,所以查找第 index+1 个节点
            for (int i = 0; i <= index; i++) {
                currentNode = currentNode.next;
            }
            return currentNode.val;
        }
    
        //在链表最前面插入一个节点,等价于在第0个元素前添加
        public void addAtHead(int val) {
            addAtIndex(0, val);
        }
    
        //在链表的最后插入一个节点,等价于在(末尾+1)个元素前添加
        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++;//添加一个元素,对应size也要++
            //找到要插入节点的前驱
            ListNode pred = head;
            for (int i = 0; i < index; i++) {
                pred = pred.next;
            }
            ListNode toAdd = new ListNode(val);
            toAdd.next = pred.next;
            pred.next = toAdd;
        }
    
        //删除第index个节点
        public void deleteAtIndex(int index) {
            if (index < 0 || index >= size) {
                return;
            }
            size--;//删除一个元素,对应size也要--
            if (index == 0) {//如果删除的是首结点
                head = head.next;
    	    return;
            }
            ListNode pred = head;
            for (int i = 0; i < index ; i++) {
                pred = pred.next;
            }
            pred.next = pred.next.next;
        }
    
        public static void main(String[] args) {
            MyLinkedList myLinkedList = new MyLinkedList();
            myLinkedList.addAtHead(1);
            myLinkedList.addAtTail(3);
            myLinkedList.addAtIndex(1, 2);    // 链表变为 1->2->3
            myLinkedList.get(1);              // 返回 2
            myLinkedList.deleteAtIndex(0);    // 现在,链表变为 1->3
            System.out.println(myLinkedList.get(1));              // 返回 3
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92

    206. 反转链表

    微软 Microsoft、亚马逊、奥多比 Adobe

    给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

    示例 1:

    img

    输入:head = [1,2,3,4,5]
    输出:[5,4,3,2,1]
    
    • 1
    • 2

    示例 2:

    img

    输入:head = [1,2]
    输出:[2,1]
    
    • 1
    • 2

    示例 3:

    输入:head = []
    输出:[]
    
    • 1
    • 2

    提示:

    • 链表中节点的数目范围是 [0, 5000]
    • -5000 <= Node.val <= 5000

    **进阶:**链表可以选用迭代或递归方式完成反转。你能否用两种方法解决这道题?

    教程:https://programmercarl.com/0206.%E7%BF%BB%E8%BD%AC%E9%93%BE%E8%A1%A8.html

    视频:https://www.bilibili.com/video/BV1nB4y1i7eL

    方法一:双指针法

    思路img

    复杂度分析

    • 时间复杂度: O ( n ) O(n) O(n)
    • 空间复杂度: O ( 1 ) O(1) O(1)
    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 pre = null;
            ListNode cur = head;
            ListNode temp = null;
            while(cur!=null){
                temp = cur.next;
                cur.next=pre;后一个指针指向前一个指针
                pre=cur;
                cur=temp;
            }
            return pre;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
  • 相关阅读:
    MySQL加密的几种常见方式
    养殖自动化管理系统:开启智慧养殖新篇章
    MongDB的高级查询
    谷粒学院——Day09【整合阿里云视频点播】
    【云开发】- 在小程序端操作云存储
    条例13~17(资源管理)
    oracle-使用PLSQL工具自行修改用户密码
    英语学习笔记30——What must I do?
    软件配置 | Git下载、安装及卸载
    12.1.5 将查询结果插入另一个表中
  • 原文地址:https://blog.csdn.net/Catherinemin/article/details/134084162