当前位置: 首页 > article >正文

代码随想录算法训练营第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]

示例 2:

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

示例 3:

输入:head = [7,7,7,7], val = 7
输出:[]

提示:

  • 列表中的节点数目在范围 [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;
    }

}

看一个例子,输入: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;
    }
}

这个代码是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

提示:

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

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

    //获取第index个节点的数值,注意index是从0开始的,第0个节点就是头结点
    public int get(int index) {
        //如果index非法,返回-1
        if (index < 0 || index >= size) {
            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++;
        //找到要插入节点的前驱
        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--;
        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;
    }
}

206. 反转链表

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

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

示例 1:

img

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

示例 2:

img

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

示例 3:

输入:head = []
输出:[]

提示:

  • 链表中节点的数目范围是 [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;
    }
}

http://www.kler.cn/a/106655.html

相关文章:

  • 【2025最新计算机毕业设计】基于SpringBoot+Vue电脑在线装机指南教程网站【源码+文档】
  • 【包教包会】CocosCreator3.x框架——带翻页特效的场景切换
  • 七:如何用Chrome的Network面板分析HTTP报文
  • spring boot整合https协议
  • opc da 服务器数据 转 IEC61850项目案例
  • 策略模式、状态机详细解读
  • sqoop连接MYSQL报错处理
  • 基于PyTorch的MNIST手写体分类实战
  • Mac版好用的Git客户端 Fork 免激活
  • c# 操作word中的表格 批量复制和批量插入
  • 修改svc的LoadBalancer的IP引发的惨案
  • Nacos的安装和实操
  • 2023NOIP A层联测19-多边形
  • 基于nodejs+vue人脸识别考勤管理系统的设计与实现
  • 正点原子嵌入式linux驱动开发——Linux LCD驱动
  • day06-Flex布局
  • 微信小程序input输入字母自动转大写不生效问题解决
  • 一文搞懂 MineCraft 服务器启动操作和常见问题 2023年10月
  • CentOS卸载LVM磁盘的方法
  • centos格式化硬盘/u盘的分区为NTFS格式
  • 【网安大模型专题10.19】论文6:Java漏洞自动修复+数据集 VJBench+大语言模型、APR技术+代码转换方法+LLM和DL-APR模型的挑战与机会
  • 接口测试及接口测试常用的工具
  • nodejs+vue旅游推荐系统-计算机毕业设计
  • Spring的BeanFactory与FactoryBean的区别
  • MySQL - 为什么InnoDB选择B+树索引?Change buffer?
  • Docker 入门