代码随想录之链表刷题总结
目录
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.链表理论基础 链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域…...

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

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

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

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

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

#渗透测试#SRC漏洞挖掘# 信息收集-常见端口及谷歌语法
免责声明 本教程仅为合法的教学目的而准备,严禁用于任何形式的违法犯罪活动及其他商业行为,在使用本教程前,您应确保该行为符合当地的法律法规,继续阅读即表示您需自行承担所有操作的后果,如有异议,请立即停…...

如何使用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. 引言: 本文图文深入介绍Oracle DB link,先介绍基本概念。 2.DB link的定义 数据库链接(Database Link,简称 DB Link)是 Oracle 数据库中的一个重要功能。它是一种在一个 Oracle 数据库实例中访问另一个 Oracle 数…...

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

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

OpenCV视觉分析之目标跟踪(7)目标跟踪器类TrackerVit的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 VIT 跟踪器由于特殊的模型结构而变得更快且极其轻量级,模型文件大约为 767KB。模型下载链接:https://github.com/opencv/…...

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

18.网工入门篇--------今天介绍下广域网技术
广域网(Wide Area Network,WAN)是一种能连接多个城市、国家甚至横跨几个洲,提供远距离通信的网络。以下是关于广域网技术的详细介绍: 广域网的组成: 结点交换机:这是广域网的核心设备࿰…...

鸿蒙原生应用开发及部署:首选华为云,开启HarmonyOS NEXT App新纪元
目录 前言 HarmonyOS NEXT:下一代操作系统的愿景 1、核心特性和优势 2、如何推动应用生态的发展 3、对开发者和用户的影响 华为云服务在鸿蒙原生应用开发中的作用 1、华为云ECS C系列实例 (1)全维度性能升级 (2ÿ…...

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. 卸载(可选) 2. 安装docker 3. 启动docker 4. 配置镜像加速 …...

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

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

【数据结构-邻项消除】力扣735. 小行星碰撞
给定一个整数数组 asteroids,表示在同一行的小行星。 对于数组中的每一个元素,其绝对值表示小行星的大小,正负表示小行星的移动方向(正表示向右移动,负表示向左移动)。每一颗小行星以相同的速度移动。 找…...

002-Kotlin界面开发之Kotlin旋风之旅
Kotlin旋风之旅 Compose Desktop中哪些Kotlin知识是必须的? 在学习Compose Desktop中,以下Kotlin知识是必须的: 基础语法:包括变量声明、数据类型、条件语句、循环等。面向对象编程:类与对象、继承、接口、抽象类等。…...

VMware Workstation Pro for Personal Use (For Windows)
这是从broadcom.com网下载的个人版本的Vmware 17.6.1,存分享不要分。 VMware-workstation-full-17.6.1-24319023.exe(447.93 MB) Build Number: 24319023 Oct 08, 2024 07.33AM SHA2: f95429e395a583eb5ba91f09b040e2f8c53a5e7aa37c4c6bfcaf82115a8…...

论文 | PROMPTAGATOR : FEW-SHOT DENSE RETRIEVAL FROM 8 EXAMPLES
1. 背景信息 在信息检索领域,传统的方法往往依赖于大量的标注数据来训练模型,以便在各种任务中表现良好。然而,许多实际应用中的监督数据是有限的,尤其是在不同的检索任务中。最近的研究开始关注如何从一个拥有丰富监督数据的任务…...

使用 Github 进行项目管理
GitHub 是一个广泛使用的代码托管和协作平台,它提供了强大的工具来支持项目管理和团队协作。在项目开发和工作中,避免不了 Github 的使用,然鹅我一直没有稍微系统地学习过 github 的整个工作流程,对这些操作都是一知半解的&#x…...

企业SRC挖掘选择与信息收集指南
内容预览 ≧∀≦ゞ 企业SRC挖掘选择与信息收集指南导语1. 企业SRC的选择2. 信息收集2.1 集团与子公司2.2 小程序与APP2.3 Web端信息收集 3. 信息收集常用模板总结 企业SRC挖掘选择与信息收集指南 导语 近年来,企业的安全响应中心(SRC)已逐渐…...

Golang | Leetcode Golang题解之第524题通过删除字母匹配到字典里最长单词
题目: 题解: func findLongestWord(s string, dictionary []string) (ans string) {m : len(s)f : make([][26]int, m1)for i : range f[m] {f[m][i] m}for i : m - 1; i > 0; i-- {f[i] f[i1]f[i][s[i]-a] i}outer:for _, t : range dictionary …...

【DBeaver】连接带kerberos的hive[Apache|HDP]
目录 一、安装配置Kerberos客户端环境 1.1 安装Kerberos客户端 1.2 环境配置 二、基于Cloudera驱动创建连接 三、基于Hive原生驱动创建连接 一、安装配置Kerberos客户端环境 1.1 安装Kerberos客户端 在Kerberos官网下载,地址如下:https://web.mit.edu/kerberos…...

Unity3D 开发教程:从入门到精通
Unity3D 开发教程:从入门到精通 Unity3D 是一款强大的跨平台游戏引擎,广泛应用于游戏开发、虚拟现实、增强现实等领域。本文将详细介绍 Unity3D 的基本概念、开发流程以及一些高级技巧,帮助你从零基础到掌握 Unity3D 开发。 目录 Unity3D…...

文件操作和 IO(一):文件基础知识 文件系统操作 => File类
目录 1. 什么是文件 1.1 概念 1.2 硬盘, 内存, 寄存器之间的区别 1.3 机械硬盘和固态硬盘 2. 文件路径 2.1 绝对路径 2.2 相对路径 3. 文件分类 4. File 类 4.1 属性 4.2 构造方法 4.3 方法 1. 什么是文件 1.1 概念 狭义上的文件: 保存在硬盘上的文件广义的上的文…...