力扣707设计链表

news2024/10/5 22:24:29

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

单链表中的节点应该具备两个属性: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

思路

删除链表节点:

链表-删除节点

添加链表节点:

链表-添加节点

这道题目设计链表的五个接口:

  • 获取链表第index个节点的数值
  • 在链表的最前面插入一个节点
  • 在链表的最后面插入一个节点
  • 在链表第index个节点前面插入一个节点
  • 删除链表的第index个节点

可以说这五个接口,已经覆盖了链表的常见操作,是练习链表操作非常好的一道题目

链表操作的两种方式:

  1. 直接使用原来的链表来进行操作。
  2. 设置一个虚拟头结点在进行操作。

下面采用的设置一个虚拟头结点(这样更方便一些,大家看代码就会感受出来)

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

java

//单链表
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;
    }
}

//双链表
class ListNode{
    int val;
    ListNode next,prev;
    ListNode() {};
    ListNode(int val){
        this.val = val;
    }
}


class MyLinkedList {  

    //记录链表中元素的数量
    int size;
    //记录链表的虚拟头结点和尾结点
    ListNode head,tail;
    
    public MyLinkedList() {
        //初始化操作
        this.size = 0;
        this.head = new ListNode(0);
        this.tail = new ListNode(0);
        //这一步非常关键,否则在加入头结点的操作中会出现null.next的错误!!!
        head.next=tail;
        tail.prev=head;
    }
    
    public int get(int index) {
        //判断index是否有效
        if(index<0 || index>=size){
            return -1;
        }
        ListNode cur = this.head;
        //判断是哪一边遍历时间更短
        if(index >= size / 2){
            //tail开始
            cur = tail;
            for(int i=0; i< size-index; i++){
                cur = cur.prev;
            }
        }else{
            for(int i=0; i<= index; i++){
                cur = cur.next; 
            }
        }
        return cur.val;
    }
    
    public void addAtHead(int val) {
        //等价于在第0个元素前添加
        addAtIndex(0,val);
    }
    
    public void addAtTail(int val) {
        //等价于在最后一个元素(null)前添加
        addAtIndex(size,val);
    }
    
    public void addAtIndex(int index, int val) {
        //index大于链表长度
        if(index>size){
            return;
        }
        //index小于0
        if(index<0){
            index = 0;
        }
        size++;
        //找到前驱
        ListNode pre = this.head;
        for(int i=0; i<index; i++){
            pre = pre.next;
        }
        //新建结点
        ListNode newNode = new ListNode(val);
        newNode.next = pre.next;
        pre.next.prev = newNode;
        newNode.prev = pre;
        pre.next = newNode;
        
    }
    
    public void deleteAtIndex(int index) {
        //判断索引是否有效
        if(index<0 || index>=size){
            return;
        }
        //删除操作
        size--;
        ListNode pre = this.head;
        for(int i=0; i<index; i++){
            pre = pre.next;
        }
        pre.next.next.prev = pre;
        pre.next = pre.next.next;
    }
}

/**
 * Your MyLinkedList object will be instantiated and called as such:
 * MyLinkedList obj = new MyLinkedList();
 * int param_1 = obj.get(index);
 * obj.addAtHead(val);
 * obj.addAtTail(val);
 * obj.addAtIndex(index,val);
 * obj.deleteAtIndex(index);
 */

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/768245.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring Security OAuth2.0(5):Spring Security工作原理

文章目录 工作原理结构总览 认证流程授权流程AuthenticationProviderUserDetailsServicePasswordEncoder如何使用BCryptPasswordEncoder 授权流程授权流程授权决策 工作原理 结构总览 \qquad Spring Security 所解决的问题就是安全访问控制&#xff0c;而安全访问控制功能其实…

3.12 Bootstrap 超大屏幕(Jumbotron)

文章目录 Bootstrap 超大屏幕&#xff08;Jumbotron&#xff09; Bootstrap 超大屏幕&#xff08;Jumbotron&#xff09; 下面将讲解 Bootstrap 支持的另一个特性&#xff0c;超大屏幕&#xff08;Jumbotron&#xff09;。顾名思义该组件可以增加标题的大小&#xff0c;并为登陆…

MySQL-多表设计-一对一多对多

一对一 案例&#xff1a;用户 与身份证信息 的关系关系&#xff1a;一对一关系&#xff0c;多用于单表拆分&#xff0c;将一张表的基础字段放在一张表中&#xff0c;其它字段放在另一张表中&#xff0c;以提高操作效率实现&#xff1a;在任意一方加入外键&#xff0c;关联另一…

Linux小程序:倒计时和进度条

Linux小程序 在Linux中我们实现两个小程序来体会\r和\n的区别&#xff0c;以及缓冲区是什么&#xff1f; 文章目录 Linux小程序前言回车和换行的区别缓冲区 小程序的实现倒计时程序进度条程序 总结 前言 回车和换行的区别 对于 \r 和 \n 的理解&#xff1a; \n 表示换行且回…

创建git仓库连接上传全过程记录

1.初始化仓库 使用git init命令在一个新文件夹里初始化仓库 2.在github创建仓库 3.连接git仓库 采用命令是 git remote add origin 仓库地址4.添加文件进行测试 5.选择要上传的文件 一般选择git add .命令 6.提交文件到本地仓库 git commit -m "备注信息"7.…

RISCV - 1 RV32/64G指令集清单

RISCV - 1 RV32/64G指令集清单 1 RV32/64G指令类型2 RV32I 基本指令集3 RV64I基础指令集&#xff08;除了RV32I)4 RV32/RV64 Zifencei标准扩展5 RV32/RV64 Zicsr标准扩展6 RV32M标准扩展7 RV64M标准扩展&#xff08;除了RV32M)8 RV32A标准扩展9 RV64A标准扩展&#xff08;除了R…

php实现站群软件权限管理功能示例

1.管理员页面RBAC.php <!DOCTYPE html> <html> <head> <meta charset"UTF-8"> <title>权限管理</title> <script src"bootstrap/js/jquery-1.11.2.min.js"></script> </head>…

jenkins war包 centos启动安装指导

文章目录 步骤1&#xff1a;进入官网&#xff0c;下载到Jenkins的war包1.1 放置在指定位置1.2 放置安装包和创建文件放置路径1.3 检查环境1.4 配置启动命令和结束命令 步骤2&#xff1a; 启动后进入到Jenkins页面2.1 安装插件&#xff0c;例如流水线2.2 依然出现安装插件失败的…

ReWorks系统加载启动

1、通过网络或本地加载启动 配置tftp网络 网卡属性配置为100Mbps全双工 配置串口 目标板上电进入uboot 设置PC机IP、目标机IP、目标机MAC地址 加载文件并启动 固化系统镜像至SD卡 需支持挂载文件系统&#xff0c;并启动ftp服务 选择SD卡、文件系统、ftp服务 挂接SD卡 也可以…

动态规划---最大字段和

描述 给出 n 个整数序列&#xff08;可能为负数&#xff09;组成的序列 a1​, a2​,...,an​&#xff0c;求该序列形如 的子段和的最大值。当所有整数均为负数时&#xff0c;定义最大子段和为 0 。 输入描述 多测试用例。每个测试用例 2 行&#xff1a; 第一行是序列的个数…

Day977.除了授权码许可类型,OAuth 2.0还支持什么授权流程? -OAuth 2.0

除了授权码许可类型&#xff0c;OAuth 2.0还支持什么授权流程&#xff1f; Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于除了授权码许可类型&#xff0c;OAuth 2.0还支持什么授权流程&#xff1f;的内容。 授权码许可的流程最完备、最安全没错儿&#xff0c;但它…

将大模型集成到语音识别系统中的例子

概述 本文旨在探索将大型语言模型&#xff08;LLMs&#xff09;集成到自动语音识别&#xff08;ASR&#xff09;系统中以提高转录准确性的潜力。 文章介绍了目前的ASR方法及其存在的问题&#xff0c;并对使用LLMs的上下文学习能力来改进ASR系统的性能进行了合理的动机论证。 本…

【分布式缓存】springboot整合jetcache使用详解

目录 一、前言 二、多级缓存问题 2.1 缓存分类 2.1.1 本地缓存 2.1.2 分布式缓存 2.2 独立缓存的问题 2.2.1 缓存雪崩问题 2.2.2 对宽带压力大 2.2.3 运行效率低 2.3 多级缓存方案 2.3.1 多级缓存实践方案推荐 三、jetcache介绍 3.1 jetcache概述 3.2 jetcache 特…

手写代码系列

(1)手写clearfix .clearfix:after{content:; display:table;clear:both;} (2) 手写圣杯模型 (3)手写深拷贝 递归 const obj3={age:20,name:xxx,address:{} }, arr:[a,b,c] function deeepClone(obj={}){} (4)手写画图解释原型链(class的原型和本质)

vue3 引入dataV 报错,使用patch-package记录插件包 node_modeule 修改记录。 vite 版DataV

开发数字大屏功能&#xff0c;引用dataV UI组件库比较好用&#xff0c;目前分为Vue2 和 Vue3 两个版本。 Vue2 --DataV版本 yarn add jiaminghi/data-viewVue3 --DataV版本 yarn add dataview/datav-vue3vite – --DataV版本 //不想动手改的&#xff0c;也可以使用此版本&a…

2、常用布局控件

首先,展开工具箱。注意这里打开的文件要是窗体文件,就是Form1,cs,否则工具箱列表将是空的。 然后选到容器,这里我们就可以看到常用的布局控件了。 使用的时候直接从左边拉到右边即可 注意:布局是支持嵌套的。 这里我们逐个介绍。 第一个是指针,这个不是布局控件,就是…

LCD-STM32液晶显示中英文-(7.字模及显示原理)

目录 字模介绍 什么是字模 字模的构成 字模显示原理 字模制作 如何制作字模 字模寻址公式 存储字模文件 字模介绍 什么是字模 有了编码&#xff0c;我们就能在计算机中处理、存储字符了&#xff0c;但是如果计算机处理完字符后直接以编码的形式输出&#xff0c;人类将难…

python解析器和pycharm编译器安装

python解析器下载地址&#xff1a;https://www.python.org/getit/ 注意事项&#xff1a; 1. 建议下载3.6以以上的版本&#xff0c; 2. 官网下载比较慢&#xff0c;可以自行寻找其它网站下载&#xff0c; 3. 建议使用.exe安装包方式下载安装 下载完成后双击运行 验证是否安装成功…

使用Python提取TripAdvisor数据:探索旅游的新途径

前言 大家早好、午好、晚好吖 ❤ ~欢迎光临本文章 猫途鹰&#xff08;TripAdvisor&#xff09;是一个旅游点评网站&#xff0c;如果您想要爬取该网站的数据&#xff0c;需要了解该网站的访问规则和爬取限制。 环境使用: Python 3.8 Pycharm 代码实现 针对猫途鹰网站&#…

Echarts柱状图横向滚动,如何实现从后往前滚动

Echarts柱状图横向滚动&#xff0c;如何实现从后往前滚动 设置开始和结束的横坐标&#xff0c;设置产生横向滚动条