LeetCode 707. 设计链表

news2024/9/27 2:27:02

LeetCode 707. 设计链表

难度: m i d d l e \color{orange}{middle} middle


题目描述

设计链表的实现。您可以选择使用单链表或双链表。单链表中的节点应该具有两个属性: v a l val val n e x t next next v a l val val 是当前节点的值, n e x t next next 是指向下一个节点的指针/引用。如果要使用双向链表,则还需要一个属性 p r e v prev prev 以指示链表中的上一个节点。假设链表中的所有节点都是 0-index 的。

在链表类中实现这些功能:

  • get(index):获取链表中第 i n d e x index index 个节点的值。如果索引无效,则返回 − 1 -1 1
  • addAtHead(val):在链表的第一个元素之前添加一个值为 v a l val val 的节点。插入后,新节点将成为链表的第一个节点。
  • addAtTail(val):将值为 v a l val val 的节点追加到链表的最后一个元素。
  • addAtIndex(index,val):在链表中的第 i n d e x index index 个节点之前添加值为 v a l val val 的节点。如果 i n d e x index index 等于链表的长度,则该节点将附加到链表的末尾。如果 i n d e x index index 大于链表长度,则不会插入节点。如果 i n d e x index index小于0,则在头部插入节点。
  • deleteAtIndex(index):如果索引 i n d e x index index 有效,则删除链表中的第 i n d e x index index 个节点。

示例:

MyLinkedList linkedList = new MyLinkedList();
linkedList.addAtHead(1);
linkedList.addAtTail(3);
linkedList.addAtIndex(1,2);   //链表变为1-> 2-> 3
linkedList.get(1);            //返回2
linkedList.deleteAtIndex(1);  //现在链表是1-> 3
linkedList.get(1);            //返回3

提示:

  • 0 < = i n d e x , v a l < = 1000 0 <= index, val <= 1000 0<=index,val<=1000
  • 请不要使用内置的 LinkedList 库。
  • g e t get get, a d d A t H e a d addAtHead addAtHead, a d d A t T a i l addAtTail addAtTail, a d d A t I n d e x addAtIndex addAtIndex d e l e t e A t I n d e x deleteAtIndex deleteAtIndex 的操作次数不超过 2000 2000 2000

算法1

(单链表)

实现单向链表,即每个节点仅存储本身的值和后继节点。除此之外,我们还需要一个哨兵(sentinel)节点作为头节点,和一个 size 参数保存有效节点数。如下图所示。

在这里插入图片描述

复杂度分析

  • 时间复杂度 O ( n ) O(n) O(n),初始化消耗 O ( 1 ) O(1) O(1)get 消耗 O ( i n d e x ) O(index) O(index)addAtHead 消耗 O ( 1 ) O(1) O(1)addAtTail 消耗 O ( n ) O(n) O(n),其中 n 为链表当前长度。

  • 空间复杂度 : 所有函数的单次调用空间复杂度均为 O ( 1 ) O(1) O(1),总体空间复杂度为 O ( n ) O(n) O(n)

C++ 代码

class MyLinkedList {
public:

    struct Node {
        int val;
        Node* next;
        Node(int _val): val(_val), next(NULL) {}
    }*head;

    MyLinkedList() {
        head = NULL;
    }

    int get(int index) {
        if (index < 0) return -1;
        auto p = head;
        for (int i = 0; i < index && p; i ++ ) p = p->next;
        if (!p) return -1;
        return p->val;
    }

    void addAtHead(int val) {
        auto cur = new Node(val);
        cur->next = head;
        head = cur;
    }

    void addAtTail(int val) {
        if (!head) head = new Node(val);
        else {
            auto p = head;
            while (p->next) p = p->next;
            p->next = new Node(val); 
        }

    }

    void addAtIndex(int index, int val) {
        if (index <= 0) addAtHead(val);
        else {
            int len = 0;
            for (auto p = head; p; p = p->next) len ++ ;
            if (index == len) addAtTail(val);
            else if (index < len) {
                auto p = head;
                for (int i = 0; i < index - 1; i ++ ) p = p->next;
                auto cur = new Node(val);
                cur->next = p->next;
                p->next = cur;
            } 
        }       
    }

    void deleteAtIndex(int index) {
        int len = 0;
        for (auto p = head; p; p = p->next) len ++ ;
        if (index >= 0 && index < len) {
            if (index == 0) head = head->next;
            else {
                auto p = head;
                for (int i = 0; i < index - 1; i ++ ) p = p->next;
                p->next = p->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);
 */


算法2

(双链表)

实现双向链表,即每个节点要存储本身的值,后继节点和前驱节点。除此之外,需要一个哨兵节点作为头节点 head 和一个哨兵节点作为尾节点 tail。仍需要一个 size 参数保存有效节点数。如下图所示。

在这里插入图片描述

复杂度分析

  • 时间复杂度 O ( n ) O(n) O(n),初始化消耗 O ( 1 ) O(1) O(1)get 消耗 O ( i n d e x ) O(index) O(index)addAtHead 消耗 O ( 1 ) O(1) O(1)addAtTail 消耗 O ( n ) O(n) O(n),其中 n 为链表当前长度。

  • 空间复杂度 : 所有函数的单次调用空间复杂度均为 O ( 1 ) O(1) O(1),总体空间复杂度为 O ( n ) O(n) O(n)

C++ 代码

class MyLinkedList {
public:

    //双链表
    struct Node {
        Node *left, *right;
        int val;

        Node(int _val) {
            val = _val;
            left = right = NULL;
        }
    }*head, *tail;

    //表示节点的个数
    int size;

    //初始化
    MyLinkedList() {
        size = 0;
        head = new Node(INT_MIN), tail = new Node(INT_MAX);
        head->right = tail;
        tail->left = head;
    }
    
    int get(int index) {
        if (index < 0 || index >= size)
            return -1;
        
        //找到第 index 个节点,head是虚拟节点,所以 i <= index
        auto p = head;
        for (int i = 0; i <= index; i ++) p = p->right;
        return p->val;  
    
    }
    
    void addAtHead(int val) {
        auto t = new Node(val);
        size ++;
        t->right = head->right, head->right->left = t;
        t->left = head, head->right = t;
    }
    
    void addAtTail(int val) {
        auto t = new Node(val);
        size ++;
        tail->left->right = t, t->left = tail->left;
        t->right = tail, tail->left = t;
    }
    
    void addAtIndex(int index, int val) {
        if (index > size) return;
        else if (index == size) addAtTail(val);
        else if (index < 0) addAtHead(val);
        else {
            auto p = head;
            //在链表中的第 index 个节点之前添加值为 val  的节点,所以找到第 index-1 节点,在后面插入一个节点
            for (int i = 0; i < index; i ++)
                p = p->right;

            auto q = p->right;

            size ++;
            auto t = new Node(val);
            t->right = q, q->left = t;
            p->right = t, t->left = p;

        }
    }   
    
    void deleteAtIndex(int index) {
        if (index < 0 || index >= size) return;

        auto p = head;
        // p 是虚拟节点,p点是要删除的节点
        for (int i = 0; i <= index; i ++) p = p->right;
        size --;
        p->right->left = p->left;
        p->left->right = p->right;
        delete p;
    }
};

/**
 * 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/367051.html

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

相关文章

FastCGI sent in stderr: "PHP message: PHP Fatal error

服务器php7.2卸载安装7.4之后,打开网站一直无法访问,查看nginx错误日志发现一直报这个错误:2023/02/23 11:12:55 [error] 4735#0: *21 FastCGI sent in stderr: &#xff02;PHP message: PHP Fatal error: Uncaught ReflectionException: Class translator does not exist in …

OpenGL超级宝典学习笔记:原子计数器

前言 本篇在讲什么 本篇为蓝宝书学习笔记 原子计数器 本篇适合什么 适合初学Open的小白 本篇需要什么 对C语法有简单认知 对OpenGL有简单认知 最好是有OpenGL超级宝典蓝宝书 依赖Visual Studio编辑器 本篇的特色 具有全流程的图文教学 重实践&#xff0c;轻理论&#…

比特数据结构与算法(第四章_中)堆的分步构建

不清楚堆的概念和性质公式可以先到上一篇看看链接&#xff1a;比特数据结构与算法&#xff08;第四章_上&#xff09;树和二叉树和堆的概念及结构_GR C的博客-CSDN博客堆的逻辑结构是完全二叉树&#xff0c;物理&#xff08;存储&#xff09;结构是数组1.完整Heap.h和以前学的数…

计算机网络概述 第一部分

前言 为了准备期末考试&#xff0c;同时也是为了之后复习方便&#xff0c;特对计算机网络的知识进行了整理。本篇内容大部分是来源于我们老师上课的ppt。而我根据自己的理解&#xff0c;将老师的PPT整理成博文的形式以便大家复习查阅&#xff0c;同时对于一些不是很清楚的地方…

centos7搭建svn配置

基本概述 Apache Subversion&#xff08;简称SVN&#xff0c;svn&#xff09;&#xff0c;一个开放源代码的版本控制系统&#xff0c;相较于RCS、CVS&#xff0c;它采用了分支管理系统&#xff0c;它的设计目标就是取代CVS。互联网上很多版本控制服务已从CVS转移到Subversion。…

【Vue3源码】第五章 ref的原理 实现ref

【Vue3源码】第五章 ref的原理 实现ref 上一章节我们实现了reactive 和 readonly 嵌套对象转换功能&#xff0c;以及shallowReadonly 和isProxy几个简单的API。 这一章我们开始实现 ref 及其它配套的isRef、unRef 和 proxyRefs 1、实现ref 接受一个内部值&#xff0c;返回一…

3款实用又强的软件,值得收藏,不妨试试

1、白描 白描是一款高效准确的OCR文字识别、翻译与文件扫描软件&#xff0c;文字识别、表格识别转Excel、识别后翻译、文件扫描等功能&#xff0c;都非常方便&#xff0c;免费使用无任何广告。白描可以自动识别文档边界&#xff0c;生成清晰的扫描件&#xff0c;高效批量处理文…

Java8 Stream流Collectors.toMap当key重复时报异常(IllegalStateException)

一、问题 在使用Collectors.toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper)&#xff08;两个参数的&#xff09;时&#xff0c;如果 key 有重复&#xff0c;则会报异常&#xff08;IllegalStateException…

工赋开发者社区 | (案例)中译语通:差别化纺纱柔性智慧工厂

中译语通&#xff1a;差别化纺纱柔性智慧工厂01应用成效中译语通科技股份有限公司是一家大数据和人工智能高科技公司。在机器翻译、跨语言大数据、产业链科技、科研数据分析、数字城市和工业互联网等领域拥有自主研发的先进系统平台&#xff0c;能够为全球企业级用户提供全方位…

[oeasy]python0091_仙童公司_八叛逆_intel_8080_altair8800_牛郎星

编码进化 个人电脑 计算机 通过电话网络 进行连接 极客 利用技术 做一些有趣的尝试 极客文化 是 认真研究技术的 文化 计算机 不再是 高校和研究机构高墙里面的 神秘事物而是 生活中常见的 家用电器 ibm 蓝色巨人脚步沉重 dec 小型机不断蚕食低端市场甚至组成网络干掉大型机…

【仔细理解】计算机视觉基础1——特征提取之Harris角点

Harris角点是图像特征提取中最基本的方法&#xff0c;本篇内容将详细分析Harris角点的定义、计算方法、特点。 一、Harris角点定义 在图像中&#xff0c;若以正方形的小像素窗口为基本单位&#xff0c;按照上图可以将它们划分三种类型如下&#xff1a; 平坦区域&#xff1a;在任…

【C++】Visual Studio C++使用配置Json库文件(老爷式教学)

在visual studio中使用C调用Json的三方库有很多种办法&#xff0c;这里简述一种比较方便的方法。绝对好用&#xff0c;不好用你砍我。 文章目录在visual studio中使用C调用Json的三方库有很多种办法&#xff0c;这里简述一种比较方便的方法。绝对好用&#xff0c;不好用你砍我。…

百度前端一面高频react面试题指南

React 高阶组件、Render props、hooks 有什么区别&#xff0c;为什么要不断迭代 这三者是目前react解决代码复用的主要方式&#xff1a; 高阶组件&#xff08;HOC&#xff09;是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分&#xff0c;它是一…

Python 零基础入门必看,这些知识点你都掌握了吗?

导读 Python 作为当今最受欢迎的编程语言之一&#xff0c;几乎各个领域都会涉及到&#xff0c;所以学习 Python 自然刻不容缓&#xff01;作为一个没有接触过 Python 的小白&#xff0c;一开始要想的不是如何使用以及各种高深莫测的玩法&#xff0c;从最基础的了解以及构建环境…

node笔记

一、FS模块 fs.readFile查询文件 fs.writeFile修改文件 __dirname表示当前文件所处的目录&#xff08;双下划线&#xff09; 二、path模块 什么是path 路径模块 path模块是Node.,js 官方提供的、用来处理路径的模块。它提供了一系列的方法和属性&#xff0c;用来满足用户…

Spring 之bean的生命周期

文章目录IOCBean的生命周期运行结果实例演示实体类实例化前后置代码初始化的前后置代码application.xml总结今天我们来聊一下Spring Bean的生命周期&#xff0c;这是一个非常重要的问题&#xff0c;Spring Bean的生命周期也是比较复杂的。IOC IOC&#xff0c;控制反转概念需要…

华为OD机试题,用 Java 解【合规数组】问题

最近更新的博客 华为OD机试 - 猴子爬山 | 机试题算法思路 【2023】华为OD机试 - 分糖果(Java) | 机试题算法思路 【2023】华为OD机试 - 非严格递增连续数字序列 | 机试题算法思路 【2023】华为OD机试 - 消消乐游戏(Java) | 机试题算法思路 【2023】华为OD机试 - 组成最大数…

JAVA基础常见面试题

1.Java接口和抽象类的区别&#xff1f; 接口 接口中不能定义构造器 方法全部都是抽象方法&#xff0c;JDK8提供方法默认实现 接口中的成员都是public的 接口中定义的成员变量实际上都是常量 一个类可以实现多个接口 抽象类 抽象类中可以定义构造器 可以有抽象方法和具体…

字节序

字节序 字节序&#xff1a;字节在内存中存储的顺序。 小端字节序&#xff1a;数据的高位字节存储在内存的高位地址&#xff0c;低位字节存储在内存的低位地址 大端字节序&#xff1a;数据的低位字节存储在内存的高位地址&#xff0c;高位字节存储在内存的低位地址 bit ( 比特…

设计模式第八讲:观察者模式和中介者模式详解

一. 观察者模式1. 背景在现实世界中&#xff0c;许多对象并不是独立存在的&#xff0c;其中一个对象的行为发生改变可能会导致一个或者多个其他对象的行为也发生改变。例如&#xff0c;某种商品的物价上涨时会导致部分商家高兴&#xff0c;而消费者伤心&#xff1b;还有&#x…