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

代码随想录之链表刷题总结

目录

1.链表理论基础

2.移除链表元素

3.设计链表

4.翻转链表

5.两两交换链表中的节点

6.删除链表中的第N个节点

7.链表相交

8.环形链表


1.链表理论基础

链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思)。

链表的入口节点称为链表的头结点也就是head。

如下图所示:

链表的类型

单链表

也就是刚才所说的

双链表

单链表中的指针域只能指向节点的下一个节点。

双链表:每一个节点有两个指针域,一个指向下一个节点,一个指向上一个节点。

双链表 既可以向前查询也可以向后查询。

如图所示:

循环链表

循环链表,顾名思义,就是链表首尾相连。

循环链表可以用来解决约瑟夫环问题。

链表的存储方式

数组是在内存中是连续分布的,但是**链表在内存中不是连续分布**的。

链表是**通过指针域的指针链接在内存中各个节点**

所以链表中的节点在内存中不是连续分布的 ,而是**散乱分布在内存中的某地址上**,分配机制取决于操作系统的内存管理。

如图所示:

这个链表起始节点为2, 终止节点为7,  各个节点分布在内存的不同地址空间上,通过指针串联在一起。

链表的定义

C/C++的定义链表节点方式,如下所示:

struct ListNode {int val;//存储节点上面的元素值ListNode* next;//用于指向链表的下一个节点,初始时被设置wULL,表示当前节点是链表的末尾ListNode(int x) : val(x),next(NULL) {}//构造函数,初始化ListNode的实例,接收一个整型参数x,并将这个值赋给当前节点的val成员,//同时将next指针初始化为NULL,表示这个节点后面没有更多的节点};
/*操作示例*/
ListNode* head = new ListNode(1);//创建链表的头节点,值为1
head->next = new ListNode(2);//在头节点后面添加一个新的节点,值为2

有同学说了,我不定义构造函数行不行,答案是可以的,C++默认生成一个构造函数。

但是这个构造函数不会初始化任何成员变量,下面我来举两个例子:

通过自己定义构造函数初始化节点:

ListNode* head = new ListNode(5);

使用默认构造函数初始化节点:

ListNode* head = new ListNode();
head->val = 5;

所以如果不定义构造函数使用默认构造函数的话,在初始化的时候就不能直接给变量赋值!

链表的操作

删除节点

删除D节点,如图所示:

只要将C节点的next指针 指向E节点就可以了。

那有同学说了,D节点不是依然存留在内存里么?只不过是没有在这个链表里而已。

是这样的,所以在C++里最好是再手动释放这个D节点,释放这块内存。

其他语言例如Java、Python,就有自己的内存回收机制,就不用自己手动释放了。

添加节点

如图所示:

可以看出链表的增添和删除都是O(1)操作,也不会影响到其他节点。

但是要注意,要是删除第五个节点,需要从头节点查找到第四个节点通过next指针进行删除操作,查找的时间复杂度是O(n)。

性能分析

把链表的特性和数组的特性进行一个对比,如图所示:

数组在定义的时候,长度就是固定的,如果想改动数组的长度,就需要重新定义一个新的数组。

链表的长度可以是不固定的,并且可以动态增删, 适合数据量不固定,频繁增删,较少查询的场景。

2.移除链表元素

题目:

题意:删除链表中等于给定值 val 的所有节点。

示例 1: 输入: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 输出:[]

思路:

先设置虚拟头节点,因为第一个节点也有可能是val值,然后移除的操作其实就是val值的前一个节点直接跳过val节点,指向val的下一个节点

注意:跳过的节点记得手动释放一下内存,节省空间

代码如下:

class Solution {
public:ListNode* removeElement(ListNode* head, int val) {ListNode* dummyHead = new ListNode(0);dummyHead->next = head;ListNode* cur = dummyHead;while (cur->val != NULL) {if (cur->next->val == val) {ListNode* tmp = cur->next;cur->next = cur->next->next;delete tmp;}else {cur = cur->next;}}head = dummyHead->next;delete dummyHead;return head;}
};

3.设计链表

题目

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

注意:

注意初始定义链表的状态

自己在纸上面写一遍

注意index的区间边界,搞清楚链表中的移动大小,以便在正确的位置做插入删除操作

代码如下:

class MyLinkedList {
public:struct ListNode {int val;ListNode* next;ListNode(int val) :val(val), next(nullptr) {}};// 初始化链表MyLinkedList() {_dummyHead = new ListNode(0); // 这里定义的头结点 是一个虚拟头结点,而不是真正的链表头结点_size = 0;}//a.get(index):获取链表中第 index 个节点的值。如果索引无效,则返回 - 1。int get(int index) {if (index > (_size - 1) || index < 0) {return -1;}else {ListNode* cur = _dummyHead->next;while (index--) {cur = cur->next;}return cur->next->val;}}//b.addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。void addAtHead(int val) {ListNode* newNode = new ListNode(val);newNode->next = _dummyHead->next;_dummyHead->next = newNode;_size++;}//c.addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。void addAtTail(int val) {ListNode* newNode = new ListNode(val);ListNode* cur = _dummyHead;while (cur->next != NULL) {cur = cur->next;}newNode->next = cur;}
//d.addAtIndex(index, val):在链表中的第 index 个节点之前添加值为 val  的节点。
//如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。void addAtIndex(int index, int val) {if (index > _size) return;if (index < 0) index = 0;ListNode* newNode = new ListNode(val);ListNode* cur = _dummyHead;while (index--) {cur = cur->next;}newNode->next = cur->next;cur->next = newNode;_size++;}//e.deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。void deleteAtIndex(int index) {ListNode* cur = _dummyHead;if (index > _size - 1 || index < 0) {return;}while (index--) {cur = cur->next;}ListNode* temp = cur->next;cur->next = cur->next->next;delete temp;temp = NULL;_size--;}//打印链表void printLinkedList() {ListNode* cur = _dummyHead;while (cur->next != NULL) {cout << "cur->next-val = " << cur->next->val << endl;cur = cur->next;}cout << endl;}
public:ListNode* _dummyHead;int _size;
};

4.翻转链表

题目:

题意:反转一个单链表(是将箭头翻转,不是里面的元素进行翻转)

示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL

思路:

设置双指针法,一个pre先指向NULL,然后cur在head节点,不断更新指向

注意:

使用temp先保存cur->next,因为指向改变了,不存储的话无法继续进行

代码如下:

class Solution {
public:ListNode* reverseList(ListNode* head) {ListNode* pre = NULL;ListNode* cur = head;ListNode* temp = new ListNode(0);while (cur) {temp = cur->next;cur->next = pre;//更新pre和curpre = cur;cur = temp;}return pre;}
};

5.两两交换链表中的节点

题目:

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

思路:

按照下图中的三部进行操作即可

注意:

记得保存cur->next与cur->next->next->next的值,因为指向发生了改变

代码:

class Solution {
public:ListNode* swapPairs(ListNode* head) {ListNode* dummyhead = new ListNode(0);dummyhead->next = head;ListNode* cur = dummyhead;while (cur->next != nullptr && cur->next->next != nullptr) {ListNode* temp = cur->next;ListNode* temp1 = cur->next->next->next;/*dummyhead->next = temp1;temp1->next = temp;temp = cur->next->next->next;*///错误写法,不可取cur->next = cur->next->next;cur->next->next = temp;cur->next->next->next = temp1;cur = cur->next->next;}ListNode* result = dummyhead->next;delete dummyhead;return result;}
};

6.删除链表中的第N个节点

题目:

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

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

示例 2:

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

示例 3:

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

思路:

使用双指针法进行解决,先定义fast指针和slow指针,初始化为虚拟头节点,fast先走n步,然后俩指针一起开始移动,直到fast变为NULL停止,此时slow指向的正好是删除节点的前一个节点,这是再改变节点指向即可

注意:

slow一定要在删除节点的前一个,不然无法继续操作

对于while循环中的逻辑要充足考虑,不要漏掉情况

代码如下:

class Solution {
public:ListNode* removeNthFromEnd(ListNode* head, int n) {ListNode* dummyhead = new ListNode(0);dummyhead->next = head;ListNode* slow = dummyhead;ListNode* fast = dummyhead;while (n--&&fast->next!=nullptr) {fast = fast->next;}while (fast->next != nullptr) {slow = slow->next;fast = fast->next;}slow->next = slow->next->next;return dummyhead->next;}
};

7.链表相交

题目:

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。

图示两个链表在节点 c1 开始相交:

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 **保持其原始结构**

思路:

此时一定要充分理解链表相交,:若两个链表相交,则两个链表有共同的节点,从这个节点之后,后面的节点都会重叠,直到链表结束,若相交,则两个链表呈现Y字型

 先计算两个列表的长度差值,让curA和curB这两个指针对齐,然后再移动,判断指针是否相等

如下图:

注意:

明确链表相交是什么

判断的是指针,不是数值

代码:

class Solution {ListNode* listjiao(ListNode* headA, ListNode* headB) {ListNode* curA = headA;ListNode* curB = headB;int sizeA = 0;int sizeB = 0;while (curA != nullptr) {sizeA += 1;curA = curA->next;}while (curB != nullptr) {sizeB += 1;curB = curB->next;}if (sizeB > sizeA) {swap(sizeA, sizeB);swap(headA, headB);}int gap = sizeA - sizeB;while (gap--) {curA = curA->next;}while (curA != nullptr) {if (curA == curB) {return curA;}else {curA = curA->next;curB = curB->next;}}return NULL;}
};

8.环形链表

题目:

题意: 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

为了表示给定链表中的环,使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

说明:不允许修改给定的链表。

思路:

判断1:链表是否有环
快慢指针法,从头节点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,若相遇就是有环。
判断2:环的入口节点
分别从头节点以及相遇节点出发一个指针,每次只走一个,相遇的时候就是入口节点

注意:

最后返回的是环形入口节点

代码:

class Solution {
public:ListNode* detecCycle(ListNode* head) {ListNode* fast = head;ListNode* slow = head;//while (fast->next->next != nullptr && slow != nullptr) {//啰嗦了,可以改一下while(fast!=NULL&&fast->next!=NULL) {fast = fast->next->next;slow = slow->next;//快慢指针相遇if (fast == slow) {ListNode* index1 = head;ListNode* index2 = fast;while (index1 != index2) {index1 = index1->next;index2 = index2->next;}return index1;}}return nullptr;}
};

相关文章:

代码随想录之链表刷题总结

目录 1.链表理论基础 2.移除链表元素 3.设计链表 4.翻转链表 5.两两交换链表中的节点 6.删除链表中的第N个节点 7.链表相交 8.环形链表 1.链表理论基础 链表是一种通过指针串联在一起的线性结构&#xff0c;每一个节点由两部分组成&#xff0c;一个是数据域一个是指针域…...

Python爬虫的“京东大冒险”:揭秘商品类目信息

开篇&#xff1a;欢迎来到Python的奇幻森林 在这个数据驱动的时代&#xff0c;我们就像一群探险家&#xff0c;穿梭在数字的森林中&#xff0c;寻找着隐藏的宝藏——商品类目信息。今天&#xff0c;我们将带领你一起&#xff0c;用Python这把锋利的剑&#xff0c;深入京东的神…...

双目视觉标定——1原理与实践

0 前言 双目视觉定位是目前机器&#xff08;机器人&#xff09;等领域中使用得非常广泛的视觉定位技术&#xff0c;双目视觉是模拟人的视觉系统利用两个不同位置的摄像头的视差来确定物体的位置。由于有需要采集两个摄像头的图像共同参与计算&#xff0c;所以双目相机装配要求…...

【设计模式系列】代理模式(八)

一、什么是代理模式 代理模式&#xff08;Proxy Pattern&#xff09;是一种结构型设计模式&#xff0c;它为其他对象提供一种代理以控制对这个对象的访问。代理模式在不直接访问实际对象的情况下&#xff0c;提供了对目标对象的间接访问。通过引入一个代理对象来间接操作实际对…...

微服务架构设计的初次尝试——基于以太坊智能合约 + NestJS 微服务的游戏社区与任务市场系统:架构设计

TMDOG微服务架构设计的初次尝试——基于以太坊智能合约 NestJS 微服务的游戏社区与任务市场系统&#xff1a;架构设计 一、开发背景及目的 随着区块链技术的蓬勃发展以及去中心化概念的兴起&#xff0c;越来越多的开发者开始探索如何将区块链应用到实际业务场景中&#xff0…...

“北斗+实景三维”,助力全域社会治理

在国家治理体系和治理能力现代化的大背景下&#xff0c;全域社会治理成为提升国家治理效能的关键。“北斗实景三维”技术组合&#xff0c;为全域社会治理提供了新的技术支撑和解决方案。本文将探讨这一技术如何助力全域社会治理&#xff0c;以及其在实际应用中的潜力和挑战。 …...

#渗透测试#SRC漏洞挖掘# 信息收集-常见端口及谷歌语法

免责声明 本教程仅为合法的教学目的而准备&#xff0c;严禁用于任何形式的违法犯罪活动及其他商业行为&#xff0c;在使用本教程前&#xff0c;您应确保该行为符合当地的法律法规&#xff0c;继续阅读即表示您需自行承担所有操作的后果&#xff0c;如有异议&#xff0c;请立即停…...

如何使用java雪花算法在分布式环境中生成唯一ID?

引言 在现代分布式系统中,生成唯一标识符(ID)是一个常见的需求。传统的自增ID在分布式环境中会导致冲突,因此需要一种能够在分布式系统中生成全局唯一ID的算法。 雪花算法(Snowflake)就是为了解决这个问题而提出的一种高效的ID生成算法。本文将详细介绍雪花算法的原理、…...

【php常用公共函数】php获取指定时间段相差几小时,几分钟,几秒

实现代码 <?php function diffTime($datetime1, $datetime2) {// 确保 $datetime1 总是小于或等于 $datetime2if (strtotime($datetime1) > strtotime($datetime2)) {$tmp $datetime2;$datetime2 $datetime1;$datetime1 $tmp;}// 转换为时间戳$timestamp1 strtotim…...

图文深入介绍Oracle DB link(一)

1. 引言&#xff1a; 本文图文深入介绍Oracle DB link&#xff0c;先介绍基本概念。 2.DB link的定义 数据库链接&#xff08;Database Link&#xff0c;简称 DB Link&#xff09;是 Oracle 数据库中的一个重要功能。它是一种在一个 Oracle 数据库实例中访问另一个 Oracle 数…...

Uniswap/v2-core使用及其交易流程

Uniswap是一个开源的去中心化的交易所&#xff0c;在github上面有以下重要仓库&#xff1a; uniswap-v2-core&#xff1a; 币对池pair的核心智能合约。这个repository包含了Uniswap的币对池pair的所有核心逻辑&#xff0c;增加流动性、减少流动性等。uniswap-v2-periphery&…...

clickhouse运维篇(二):多机器手动部署ck集群

熟悉流程并且有真正部署需求可以看一下我的另一篇简化部署的文章&#xff0c;因为多节点配置还是比较麻烦的先要jdk、zookeeper&#xff0c;再ck&#xff0c;还有各种配置文件登录不同机器上手动改配置文件还挺容易出错的。 clickhouse运维篇&#xff08;三&#xff09;&#x…...

OpenCV视觉分析之目标跟踪(7)目标跟踪器类TrackerVit的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 VIT 跟踪器由于特殊的模型结构而变得更快且极其轻量级&#xff0c;模型文件大约为 767KB。模型下载链接&#xff1a;https://github.com/opencv/…...

Java 实现 RESTful 风格的 Web 服务详解

前言 RESTful&#xff08;Representational State Transfer&#xff09;风格的 API 已经成为现代 Web 服务的标准。它通过简单的 HTTP 方法和资源定位来提供了一种高度可扩展和易于维护的服务接口。Java 作为一种功能强大且广泛使用的编程语言&#xff0c;提供了多种框架来实现…...

18.网工入门篇--------今天介绍下广域网技术

广域网&#xff08;Wide Area Network&#xff0c;WAN&#xff09;是一种能连接多个城市、国家甚至横跨几个洲&#xff0c;提供远距离通信的网络。以下是关于广域网技术的详细介绍&#xff1a; 广域网的组成&#xff1a; 结点交换机&#xff1a;这是广域网的核心设备&#xff0…...

鸿蒙原生应用开发及部署:首选华为云,开启HarmonyOS NEXT App新纪元

目录 前言 HarmonyOS NEXT&#xff1a;下一代操作系统的愿景 1、核心特性和优势 2、如何推动应用生态的发展 3、对开发者和用户的影响 华为云服务在鸿蒙原生应用开发中的作用 1、华为云ECS C系列实例 &#xff08;1&#xff09;全维度性能升级 &#xff08;2&#xff…...

Spring JdbcTemplate详解

文章目录 Spring JdbcTemplate详解一、引言二、配置JdbcTemplate1、引入依赖2、配置数据库连接池3、配置JdbcTemplate 三、使用JdbcTemplate操作数据库1、添加数据2、查询数据查询某个值根据条件查询返回某个对象查询对象集合 四、总结 Spring JdbcTemplate详解 一、引言 在J…...

Docker篇(Docker安装)

目录 一、Centos7.x 1. yum 包更新到最新 2. 安装需要的软件包 3. 设置 yum 源为阿里云 4. 安装docker 5. 安装后查看docker版本 6. 设置ustc镜像源 二、CentOS安装Docker 前言 1. 卸载&#xff08;可选&#xff09; 2. 安装docker 3. 启动docker 4. 配置镜像加速 …...

Pytorch 实现图片分类

CNN 网络适用于图片识别&#xff0c;卷积神经网络主要用于图片的处理识别。卷积神经网络&#xff0c;包括一下几部分&#xff0c;输入层、卷积层、池化层、全链接层和输出层。 使用 CIFAR-10 进行训练&#xff0c; CIFAR-10 中图片尺寸为 32 * 32。卷积层通过卷积核移动进行计…...

得物App获评新奖项,正品保障夯实供应链创新水平

近日&#xff0c;得物App再度获评新奖项——“2024上海市供应链创新与应用优秀案例”。 本次奖项为上海市供应链领域最高奖项&#xff0c;旨在评选出在供应链创新成效上处于领先地位、拥有成功模式和经验的企业。今年以来&#xff0c;得物App已接连获得“上海市质量金奖”、“科…...

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

Chapter03-Authentication vulnerabilities

文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

高频面试之3Zookeeper

高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个&#xff1f;3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制&#xff08;过半机制&#xff0…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

三分算法与DeepSeek辅助证明是单峰函数

前置 单峰函数有唯一的最大值&#xff0c;最大值左侧的数值严格单调递增&#xff0c;最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值&#xff0c;最小值左侧的数值严格单调递减&#xff0c;最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...

(一)单例模式

一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...

MySQL的pymysql操作

本章是MySQL的最后一章&#xff0c;MySQL到此完结&#xff0c;下一站Hadoop&#xff01;&#xff01;&#xff01; 这章很简单&#xff0c;完整代码在最后&#xff0c;详细讲解之前python课程里面也有&#xff0c;感兴趣的可以往前找一下 一、查询操作 我们需要打开pycharm …...

ui框架-文件列表展示

ui框架-文件列表展示 介绍 UI框架的文件列表展示组件&#xff0c;可以展示文件夹&#xff0c;支持列表展示和图标展示模式。组件提供了丰富的功能和可配置选项&#xff0c;适用于文件管理、文件上传等场景。 功能特性 支持列表模式和网格模式的切换展示支持文件和文件夹的层…...

小智AI+MCP

什么是小智AI和MCP 如果还不清楚的先看往期文章 手搓小智AI聊天机器人 MCP 深度解析&#xff1a;AI 的USB接口 如何使用小智MCP 1.刷支持mcp的小智固件 2.下载官方MCP的示例代码 Github&#xff1a;https://github.com/78/mcp-calculator 安这个步骤执行 其中MCP_ENDPOI…...