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

链表理论基础

  • 链表是一种通过指针串连在一起的线性结构,每一个节点由两部分组成,一个是数据域,一个是指针域(存放指向下一个节点的指针)。最后一个节点的指针指向 null。
  • 链表的存储方式:数组在内存中是连续存储的,但链表不是连续存储的,各个节点分布在内存的不同地址空间中,用指针串联在一起。
  • 链表的定义:
// 单链表
struct ListNode{int val;  // 节点上存储的值ListNode *next;  // 指向下一个节点的指针ListNode(int x) : val(x), next(NULL) {}  // 链表节点的构造函数
};

C++ 也默认生成了一个构造函数,但这个构造函数不会初始化任何成员变量
我们自己的构造函数初始化链表节点:ListNode* head = new ListNode(5);
使用默认的构造函数初始化:ListNode* head = new ListNode(); head->val = 5;

  • 删除或增加节点:这个操作与其他节点是无关的,时间复杂度为 O(1)。但是在指定位置操作,还需要有查询操作。另外注意删除节点时只是改变指针指向,删除的节点仍在内存中,最好去主动释放。
  • 查找:链表只能从一端开始遍历,因此时间复杂度为 O(n)。
  • 性能分析:数组固定长度,连续存储,在删除或插入元素时,需要逐个移动元素,时间复杂度 O(n),但查找方便,时间复杂度 O(1)。链表长度并不固定,不连续存储,增删元素时间复杂度为 O(1),但查找 O(n)。
    因此数组适用于数据量固定,查找频繁,较少增删;链表适用于数据量不固定,增删频繁,较少查找的情景。

移除链表元素

Alt
之前我们做过一道移除链表元素的题,其难点在于数组连续存储,所以移除元素之后还需要移动其他元素保证连续。但是链表不需要保证连续存储,移除操作与其他元素无关的,其实我们直接遍历整条链表就可以了。
处理过程需要注意的问题:头节点与其他节点不同的处理办法。其他节点都是改变前一个节点的指针指向,但删除头节点的话需要不断向后更新头节点。可以添加一个虚拟节点 dummy 使得头节点的处理一般化

class Solution{
public:ListNode* removeElements(ListNode* head, int val){ListNode* dummy = new ListNode();dummy->next = head;ListNode* cur = dummy;while(cur->next != NULL){  // 用cur->next进行判断,注意删除节点释放内存的操作if(cur->next->val == val){ListNode* tmp = cur->next;cur->next = cur->next->next;delete tmp;}else  cur = cur->next;}head = dummy->next;delete dummy;return head;}
};

设计链表

Alt
注意C++语法。public 和 private 的前后顺序。维护一个虚拟节点和节点数目会使其他操作更加方便。

class MyLinkedList{
public:struct ListNode{int val;ListNode* next;ListNode(int val) : val(val), next(NULL) {}};MyLinkedList(){_dummyHead = new ListNode(0);_size = 0;}int get(int index){if(index < 0 || index > _size - 1)  return -1;ListNode* cur = _dummyHead->next;while(index--){cur = cur->next;}return cur->val;}void addAtHead(int val){ListNode* node = new ListNode(val);ListNode* cur = _dummyHead;node->next = _dummyHead->next;_dummyHead->next = node;_size++;}void addAtTail(int val){ListNode* node = new ListNode(val);ListNode* cur = _dummyHead;while(cur->next){cur = cur->next;}cur->next = node;_size++;}void addAtIndex(int index, int val){if(index < 0 || index > _size)  return;ListNode* node = new ListNode(val);ListNode* cur = _dummyHead;while(index--){cur = cur->next;}node->next = cur->next;cur->next = node;_size++;}void deleteAtIndex(int index){if(index < 0 || index > _size - 1)  return;ListNode* cur = _dummyHead;while(index--){cur = cur->next;}cur->next = cur->next->next;_size--;}
private:int _size;  // 记录链表中的节点数目ListNode* _dummyHead;  // 设计一个虚拟节点,解决头节点的问题
};

反转链表

Alt
链表只能头节点开始遍历,为了避免新建链表,可以选择使用双指针法。一个指针指向前一个节点,一个指针指向当前节点。注意:在遍历过程中会改变 next 指针的指向,所以要使用中间变量来记录下一个节点,再改变当前节点的 next 指针指向。

class Solution{
public:ListNode* reverseList(ListNode* head){if(!head)  return head;ListNode* cur = head;ListNode* pre = NULL;while(cur){ListNode* tmp = cur->next;  // 记录当前节点的下一个cur->next = pre;  // 翻转当前节点的指向pre = cur;  // 向后遍历cur = tmp;}return pre;}
};

递归法,上面的迭代法可以改写成递归。

class Solution{
public:ListNode* reverse(ListNode* pre, ListNode* cur){if(!cur)  return pre;ListNode* tmp = cur->next;cur->next = pre;return reverse(cur, tmp);}ListNode* reverseList(ListNode* head){return reverse(NULL, head);}
};

还有另一种比较难以想到的方法,是从后往前翻转。

class Solution{
public:ListNode* reverseList(ListNode* head){if(head == NULL)  return head;if(head->next == NULL)  return head;ListNode* last = reverseList(head->next);  // 把原链表末尾的节点返回(翻转后的头节点)head->next->next = head;  // 将head节点移到队列尾部,注意这一步没有改变原链表中指向head的指针,使得每层递归都能将当前head移动到队尾head->next = NULL;  // head移到队尾,指向空节点return last;}
};

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

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

相关文章

带POE网络变压器与2.5G/5G/10G网络变压器产品特点介绍

Hqst华轩盛(石门盈盛)电子导读&#xff1a;一起来了解带POE网络变压器与2.5G/5G/10G网络变压器产品特点&#xff1f; 一﹑带POE网络变压器与2.5G/5G/10G网络变压器产品特点介绍 首先、POE网络变压器产品与常规不带POE产品的区别&#xff1a; 带POE网络变压器主要要求是耐电流等…

(二)CarPlay集成开发之苹果的iAP协议

文章目录 概要协议格式鉴权流程CarPlay中的iAP2协议应用小结 概要 iAP2协议是由苹果公司定义的一种数据通信协议&#xff0c;主要用于苹果设备认证外设&#xff0c;以及与外设数据交换的一种协议 协议格式 协议格式一共分为三种类型&#xff0c;分别为握手包&#xff0c;链路…

42.接雨水 - 力扣(LeetCode)

问题描述 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。输入格式 height [0,1,0,2,1,0,1,3,2,1,2,1]输出格式 6解释 上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图&#xff0c;在这种情况下…

「优选算法刷题」:查找总价格为目标值的两个商品

一、题目 购物车内的商品价格按照升序记录于数组 price。请在购物车中找到两个商品的价格总和刚好是 target。若存在多种情况&#xff0c;返回任一结果即可。 示例 1&#xff1a; 输入&#xff1a;price [3, 9, 12, 15], target 18 输出&#xff1a;[3,15] 或者 [15,3]示例…

初始RabbitMQ(入门篇)

消息队列(MQ) 本质上就是一个队列,一个先进先出的队列,队列中存放的内容是message(消息),是一种跨进程的通信机制,用于上下游传递消息, 为什么使用MQ: 削峰填谷: MQ可以很好的做一个缓冲机制,例如在一个系统中有A和B两个应用,A是接收用户的请求的,然后A调用B进行处理. 这时…

【2023】java使用WebClient实现chatGPT调用建立web socket连接

&#x1f4bb;目录 一、介绍1、使用技术2、效果 二、代码1、前端代码2、后端代码2.1、maven依赖2.2、model2.2.1、请求接口的格式2.2.2、响应数据对象 2.3、工具类2.3.1、&#x1f534;使用WebClient调用chatgpt方法2.3.2、&#x1f7e0; webSocket连接对话方法 2.4、Controlle…

使用 OpenLLM 构建和部署大模型应用

原文&#xff1a;使用 OpenLLM 构建和部署大模型应用 - 知乎 分享主题为&#xff1a;使用 OpenLLM 快速构建和部署大语言模型的应用。OpenLLM 是一个开源的大语言模型&#xff08;LLM&#xff09;开发框架。它支持多种开源的 LLM 模型&#xff0c;并且具有内建的两个关键的 LL…

自然语言处理研究的内容

一.基础技术 1.1 词法分析 词法分析&#xff08;Lexical Analysis&#xff09;&#xff0c;也称为词法扫描或扫描器&#xff0c;是自然语言处理&#xff08;NLP&#xff09;中的基础步骤之一&#xff0c;用于将输入的文本分割成词法单元&#xff08;Token&#xff09;。词法单…

vulnhub-dc2靶场

DC2 配置环境vmware17 nat网络配置 下载地址:DC and Five86 Series Challenges - DC-1 &#xff08;似乎从2024/1/18左右找不到这个资源了&#xff09; 攻击机kali与其在同一网段下 ip:192.168.52.130 信息收集 arp-scan -l #内网探测&#xff0c;扫描目标ip发现目标ip1…

【服务器】搭建一台属于自己的服务器

​🌈个人主页:Sarapines Programmer🔥 系列专栏:【服务器】搭建网站⏰诗赋清音:云生高巅梦远游, 星光点缀碧海愁。 山川深邃情难晤, 剑气凌云志自修。 目录 1. 购买服务器和域名 1.1 购买服务器 1.1.1 阿里云服务器 1.1.2 香草云服务器 1.2 购买域名 2. 安装宝塔…

Blender——将模型及其所有纹理与材质导入unity

前期准备 参考视频&#xff1a;7分钟教会你如何将Blender的模型材质导入unity_哔哩哔哩_bilibili 实验模型官网下载地址&#xff1a;Hoi An Ancient House Model free VR / AR / low-poly 3D model CSDN下载链接&#xff1a; 【免费】Blender三维模型-古代房屋模型&#xff…

【Linux】第三十三站:日志

文章目录 一、实现一个简单的日志1.简介2.可变参数3.错误等级4.时间5.打印每一条参数6.与前面的一些代码搭配使用 二、完整代码 一、实现一个简单的日志 1.简介 我们运行代码的时候&#xff0c;我们希望有各种各样的运行时候的一些信息。这也就是日志 它一半有日志时间&…

【GitHub项目推荐--老照片变清晰】【转载】

先来看一个效果图&#xff0c;这个开源项目能把模糊爆浆的老照片 1 s 内变成清晰、高清的有色照片。 而以上这些效果&#xff0c;无需专业 PS 技能&#xff0c;只用一个网页端的 Demo、点点鼠标上传图片就能搞定。 这个修复神器&#xff0c;由腾讯 PCG ARC 实验室研发&#xf…

结构体大揭秘:代码中的时尚之选(上)

目录 结构结构的声明结构成员的类型结构体变量的定义和初始化结构体成员的访问结构体传参 结构 结构是一些值的集合&#xff0c;这些值被称为成员变量。之前说过数组是相同类型元素的集合。结构的每个成员可以是不同类型的变量&#xff0c;当然也可以是相同类型的。 我们在生活…

【系统调用IO】open、close、read、write、lseek

目录 3 系统调用IO3.1 文件描述符3.1.1 FILE结构体3.2.2 文件描述符 3.3 open、close、read、write、lseek3.3.1 文件权限3.3.2 open3.3.3 close3.3.4 read3.3.5 write3.3.6 lseek3.3.7 代码示例 文件io和标准io的区别 橙色 3 系统调用IO 3.1 文件描述符 3.1.1 FILE结构体 …

多线程编程1

一、线程的引入 上节&#xff0c;我们介绍了进程的概念&#xff0c;以及操作系统内核是如何管理进程的&#xff08;描述组织&#xff09;&#xff0c;PCB中的核心属性有哪些&#xff0c; 引入进程这个概念&#xff0c;最主要的目的&#xff0c;就是为了解决“并发编程”这样的…

JavaScript语法摘要

JavaScript语法摘要 JavaScript语法通过各种规则和组合&#xff0c;就能创建出丰富多彩的程序呢&#xff01;它包括了怎么声明和使用变量、如何定义和赋值&#xff0c;还有怎么用运算符和表达式等等。另外&#xff0c;我还发现了一些有趣的概念&#xff0c;比如关键字、注释、…

Python学习从0到1 day7 Python判断语句

路远殊途&#xff0c;祝你得偿所愿 ——24.1.21 前言 进行逻辑判断&#xff0c;是生活中常见的行为&#xff0c;同样&#xff0c;在程序中&#xff0c;进行逻辑判断也是最为基础的功能 一、布尔类型和比较运算符 1.布尔类型 进行判断&#xff0c;有两个结果&#xff0c;True、…

springboot集成COS对象存储

1.申请腾讯云存储桶 新建密钥&#xff08;后面配置要用到&#xff09; 2.编写工具类 此处使用工具类进行基本属性配置&#xff0c;也可选择在yml中配置 package com.sfy.util;import com.qcloud.cos.COSClient; import com.qcloud.cos.ClientConfig; import com.qcloud.cos.a…

基于xgboost-LGBM-SVM的病人哮喘病识别检测 数据+代码

基于xgboost-LGBM-SVM的病人哮喘病识别检测-完整代码可直接运行_哔哩哔哩_bilibili 代码: from sklearn import preprocessing import random from sklearn.model_selection import train_test_split from sklearn.preprocessing import MinMaxScaler from sklearn import pr…