二、链表(linked-list)
文章目录
- 一、定义
- 二、经典例题
- (一)[21.合并两个有序链表](https://leetcode.cn/problems/merge-two-sorted-lists/description/)
- 1.思路
- 2.复杂度分析
- 3.注意
- 4.代码
- (二)[86.分割链表](https://leetcode.cn/problems/partition-list/description/)
- 1.思路
- 2.复杂度分析
- 3.代码
- (三)[23.合并 K 个升序链表](https://leetcode.cn/problems/merge-k-sorted-lists/description/)
- 1.思路
- 2.复杂度分析
- 3.代码
- (四)[19.删除链表中的倒数第N个节点](https://leetcode.cn/problems/remove-nth-node-from-end-of-list/)
- 1.思路
- 2.复杂度分析
- 3.代码
一、定义
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。
二、经典例题
(一)21.合并两个有序链表

1.思路
根据题目描述,链表l1, l2是递增的,因此容易想到使用双指针cur1和cur2遍历两链表,根据cur1.val和cur2.val的大小关系确定节点添加顺序,两节点指针交替前进,直至遍历完毕。
同时因为两个链表都是有序的,所以,当我们遍历完一个链表,剩下的那个链表如果没到结尾,可以直接跟上。
2.复杂度分析
时间复杂度 O(M+N) : M,N别为两个链表的长度,合并操作需遍历两链表。
空间复杂度 O(1): 节点引用 dum , cur使用常数大小的额外空间。
3.注意
Dummy节点的作用是作为一个虚拟的头前节点。在不知道要返回的新链表的头结点是哪一个,它可能是原链表的第一个节点,可能在原链表的中间,也可能在最后,甚至不存在(nil)。引入Dummy节点可以涵盖所有情况,并且可以使用dummy.next返回最终需要的头结点。
4.代码
/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {ListNode* cur1 = list1;ListNode* cur2 = list2;ListNode* dummy = new ListNode(-1); // 虚拟头结点ListNode* cur = dummy;while (cur1 && cur2) {// 比较 p1 和 p2 两个指针// 将值较小的的节点接到 p 指针if (cur1 -> val > cur2 -> val) {cur -> next = cur2;cur2 = cur2 -> next;}else {cur -> next = cur1;cur1 = cur1 -> next;}cur = cur -> next; // p 指针不断前进}if (cur1) cur -> next = cur1;if (cur2) cur -> next = cur2;return dummy -> next;}
};
(二)86.分割链表
1.思路
具体来说,我们可以把原链表分成两个小链表,一个链表中的元素大小都小于 x,另一个链表中的元素都大于等于 x,最后再把这两条链表接到一起,就得到了题目想要的结果。
2.复杂度分析
时间复杂度 O(N): 其中 N为链表长度;遍历链表使用线性时间。
空间复杂度 O(1) : 假头节点使用常数大小的额外空间。
3.代码
/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* partition(ListNode* head, int x) {ListNode* dummy1 = new ListNode(-1);ListNode* dummy2 = new ListNode(-1);ListNode* small = dummy1;ListNode* big = dummy2;// 新建两个链表 small,big,分别用于添加所有节点值<x、节点值>=的节点ListNode* cur = head;while (cur) {if (cur -> val >= x) {big -> next = cur;big = big -> next;}else {small -> next = cur;small = small -> next;}cur = cur -> next;}small -> next = dummy2 -> next; // 拼接 small 和 bigbig -> next = nullptr;return dummy1 -> next;}
};
(三)23.合并 K 个升序链表
1.思路
如何快速得到 k 个节点中的最小节点,接到结果链表上?
- 这里我们就要用到 优先级队列(二叉堆) 这种数据结构,把链表节点放入一个最小堆,就可以每次获得 k 个节点中的最小节点:
优先队列 pq 中的元素个数最多是 k,所以一次 poll 或者 add 方法的时间复杂度是 O(logk);所有的链表节点都会被加入和弹出 pq,所以算法整体的时间复杂度是 O(Nlogk),其中 k 是链表的条数,N 是这些链表的节点总数。
2.复杂度分析
时间复杂度:考虑优先队列中的元素不超过 k 个,那么插入和删除的时间代价为 O(logk),这里最多有 kn 个点,对于每个点都被插入删除各一次,故总的时间代价即渐进时间复杂度为 O(kn×logk)。
空间复杂度:这里用了优先队列,优先队列中的元素不超过 k个,故渐进空间复杂度为 O(k)。
3.代码
/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:
// 时间复杂度 : O(n ∗ log(k))ListNode* mergeKLists(vector<ListNode*>& lists) {if (lists.size() == 0) return nullptr;ListNode* dummy = new ListNode(-1);ListNode* p = dummy;priority_queue<ListNode*, vector<ListNode*>, function<bool(ListNode*, ListNode*)>> pq([] (ListNode* a, ListNode* b) { return a->val > b->val; });for (auto head : lists) {if (head != nullptr) pq.push(head);}while (!pq.empty()) {ListNode* node = pq.top();pq.pop();p -> next = node;if (node -> next != nullptr)pq.push(node->next);p = p -> next;}return dummy -> next;}
};
(四)19.删除链表中的倒数第N个节点
1.思路
假设链表有 n 个节点,倒数第 k 个节点就是正数第 n - k + 1 个节点。
是的,但是算法题一般只给你一个 ListNode 头结点代表一条单链表,你不能直接得出这条链表的长度 n,而需要先遍历一遍链表算出 n 的值,然后再遍历链表计算第 n - k + 1 个节点。
也就是说,这个解法需要遍历两次链表才能得到出倒数第 k 个节点。
2.复杂度分析
3.代码
/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* removeNthFromEnd(ListNode* head, int n) {if (head == nullptr || n == 0) return nullptr;ListNode* dummy = new ListNode(-1);dummy -> next = head;ListNode* x = findFromEnd(dummy, n + 1);x -> next = x -> next -> next;return dummy -> next;}ListNode* findFromEnd(ListNode* head, int k) {// 代码见上文ListNode* slow = head;ListNode* fast = head;while (k -- && fast) {fast = fast -> next;}while (fast) {slow = slow -> next;fast = fast -> next;}return slow;}
};
相关文章:
二、链表(linked-list)
文章目录 一、定义二、经典例题(一)[21.合并两个有序链表](https://leetcode.cn/problems/merge-two-sorted-lists/description/)1.思路2.复杂度分析3.注意4.代码 (二)[86.分割链表](https://leetcode.cn/problems/partition-list…...
Android EditText筛选+选择功能开发
在日常开发中经常会遇到这种需求,EditText既需要可以筛选,又可以点击选择。这里筛选功能用的是AutoCompleteTextView,选择功能使用的是第三方库https://github.com/kongzue/DialogX。 Android AutoCompleteTextView(自动完成文本框)的基本使用…...
Linux 信号 alarm函数 setitimer函数
/*#include <unistd.h>unsigned int alarm(unsigned int seconds);功能:设置定时器。函数调用,开始倒计时,0的时候给当前的进程发送SIGALARM信号参数:倒计时的时长。。单位:秒 如果参数为0,无效返回…...
自主设计,模拟实现 RabbitMQ - 实现发送方消息确认机制
目录 一、实现发送方消息确认 1.1、需求分析 什么是发送方的消息确认? 如何实现?...
【数据结构】二叉树的·深度优先遍历(前中后序遍历)and·广度优先(层序遍历)
💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤 📃个人主页 :阿然成长日记 …...
优彩云采集器下载-免费优彩云采集器下载地址
免费优彩云采集器。您是否曾为了数据采集而感到头疼不已?是否一直在寻找一种能够轻松、高效地获取所需数据的方法?别着急,让我们一起来了解如何通过优彩云采集器解决这些问题,从而让您产生购买的欲望。 免费全自动采集发布批量管理…...
【Python】OJ 常用函数
这里写目录标题 一. math1. 求阶乘 - factorial()2. 绝对值 - fabs() 二. 容器的方法1. reverse() 三. Python 内置函数1. sort() 一. math 需要引入 math 包:import math 1. 求阶乘 - factorial() import math print(math.factorial(5))--------运行结果-------…...
【Vue】上万个字把事件处理讲解的淋漓尽致
hello,我是小索奇,精心制作的Vue系列教程持续更新哈,想要学习&巩固&避坑就一起学习吧~ 事件处理 事件的基本用法 重点内容 使用v-on:xxx缩写xxx绑定事件,其中 xxx 是事件名(回顾:v-bind缩写为冒号…...
Remmina中VNC、SSH和RDP的区别
Remmina 可以在 Linux 系统上对远程进行连接。它支持多种远程连接协议,包括 VNC(Virtual Network Computing)、SSH(Secure Shell)和 RDP(Remote Desktop Protocol)。这些协议用于实现不同类型的…...
Spring Boot实现web.xml功能
Spring Boot实现web.xml功能 1. 基于注解实现1.1 组件注册1.2 WebInitParam注解 2. 基于编码实现2.1 Servlet & Filter2.2 Listener 3. 总结 在Spring Boot中,不再需要使用传统的 web.xml 文件来配置web应用的功能,Spring Boot支持通过注解和基于代码…...
陆拾捌- 如何通过数据影响决策(三)
一、如何正确的引导别人? 引导与误导的区别是什么? 看下面这广告图 单看上面大字的结果,感觉好像真的使用过的人均觉得有好处 可如果我们看下面的细字 对111位连续14天食用(本产品)的燕麦片非重度使用者所做调研… 从…...
VMware 三种网络连接模式
VMware虚拟机的三种网络连接模式:桥接,NAT,仅主机。 网卡vmnet0,vmnet1,vmnet8区别。 在VMware中,虚拟机的网络连接主要是由VMware创建的虚拟交换机负责实现的,VMware可以根据需要创建多个虚拟网络。 VMware的虚拟网…...
Scikit-Learn快速生成分类数据集
假如你学习了新的分类算法并想进一步探索研究、尝试不同的超参数评估模型性能,但问题是你找不到好的数据集用于实验。幸运的是Scikit-Learn 提供的 make_classification() 方法可以创建不同类型的数据集,它可以生成不同类型的数据集:二分类、…...
西门子 S7 协议解析
目录 1 建立连接 2 读数据 3 写数据 1 建立连接 03 00 00 16 11 E0 00 00 00 01 00 C1 02 10 00 C2 02 03 01 C0 01 0A (第一次握手报文) 03 00 报文头 00 16 数据总长度:22 11 E0 00 00 00 01 00 C1 02 10 00 C2 02 03 01 C0 01 0A 报文结束…...
一、python解题——求序列最长递增
解题代码: import os import sys# 请在此输入您的代码 n int(input()) a list(map(int, input().split())) # 创建一个初始元素全为1的列表,用来存放每个递增序列的长度 b [1 for x in range(0, n)] # 设置num,用来控制b列表的下标 num …...
【Java 基础篇】Java线程:volatile关键字与原子操作详解
在多线程编程中,确保线程之间的可见性和数据一致性是非常重要的。Java中提供了volatile关键字和原子操作机制,用于解决这些问题。本文将深入讨论volatile关键字和原子操作的用法,以及它们在多线程编程中的重要性和注意事项。 volatile关键字…...
992. K 个不同整数的子数组
992. K 个不同整数的子数组 给定一个正整数数组 nums和一个整数 k,返回 nums 中 「好子数组」 的数目。 如果 nums 的某个子数组中不同整数的个数恰好为 k,则称 nums 的这个连续、不一定不同的子数组为 「好子数组 」。 例如,[1,2,3,1,2] 中…...
Vue 使用vue-cli构建SPA项目(超详细)
目录 一、什么是vue-cli 二,构建SPA项目 三、 运行SPA项目 前言: 在我们搭建SPA项目时候,我们必须去检查我们是否搭建好NodeJS环境 cmd窗口输入以下指令:去检查 node -v npm -v 一、什么是vue-cli Vue CLI(Vu…...
SpringBoot工程模板
spring脚手架:https://start.spring.io/ <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocati…...
学习SLAM:SLAM进阶(十)暴力更改ROS中的PCL库
话不多说,上活 1.1 为什么要这么做 项目中有依赖。。。。 1.2 安装VTK7.1.1 PCL1.8.0 略 1.3 移植到ROS 删除ROS依赖的vtk6.2和PCL1.8.0的动态链接库: liugongweiubuntu:~$ sudo mv /usr/lib/x86_64-linux-gnu/libvtk* Desktop/lib/ [sudo] password fo…...
SpringAI集成Ollama实战:从零构建本地AI对话服务
1. 环境准备:搭建Ollama本地AI模型服务 想要在本地运行AI对话服务,首先需要部署Ollama这个轻量级的大模型运行环境。Ollama最大的优势在于它能让开发者在普通配置的电脑上就能运行各种开源大模型,而不需要昂贵的GPU服务器。 安装过程非常简单…...
PyTorch 2.8镜像环境配置:CUDA 12.4与cuDNN 8+版本兼容性验证指南
PyTorch 2.8镜像环境配置:CUDA 12.4与cuDNN 8版本兼容性验证指南 1. 镜像环境概述 PyTorch 2.8深度学习镜像是一个经过深度优化的通用计算环境,专为现代AI工作负载设计。这个镜像最显著的特点是完美适配了NVIDIA最新的CUDA 12.4和cuDNN 8版本ÿ…...
Nginx + FFmpeg 核心配置
Nginx FFmpeg 核心配置(2 种最实用方案)我给你最简、能直接用的配置,不用你自己改半天,分两种场景:Nginx 接收 FFmpeg 推流(直播)Nginx 调用 FFmpeg 自动转码(高清 / 标清ÿ…...
无需安装jupyter notebook,在快马平台5分钟搭建你的第一个数据分析原型
今天想和大家分享一个快速搭建数据分析原型的经验。作为一个经常需要验证想法的数据分析师,最头疼的就是每次换电脑或重装系统后配置Jupyter Notebook环境的过程。最近发现了一个超省心的解决方案,不用本地安装就能直接开搞数据分析。 为什么选择云端Ju…...
旧Mac如何重获新生?开源工具实现系统升级完整指南
旧Mac如何重获新生?开源工具实现系统升级完整指南 【免费下载链接】OpenCore-Legacy-Patcher Experience macOS just like before 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 随着苹果不断推出新的macOS版本,许多…...
Memos笔记数据安全吗?手把手教你配置自动备份到GitHub/对象存储(防丢指南)
Memos数据安全全攻略:从本地备份到云端同步的完整方案 Memos作为一款轻量级开源笔记工具,凭借其简洁界面和本地存储特性赢得了不少用户青睐。但数据安全始终是悬在每位用户心头的一把剑——服务器宕机、硬盘损坏、误操作删除都可能让珍贵笔记瞬间消失。本…...
实战分享:如何用Altium Designer高效搞定PCB的定位孔、散热孔和屏蔽孔?
Altium Designer实战:PCB定位孔、散热孔与屏蔽孔的高效设计指南 在PCB设计领域,机械孔的设计往往被工程师视为"简单任务"而草率处理,直到量产时才发现定位偏差、散热不足或EMI超标等问题。作为从业十年的硬件设计师,我曾…...
League-Toolkit技术解析:从原理到实践的全方位指南
League-Toolkit技术解析:从原理到实践的全方位指南 【免费下载链接】League-Toolkit 兴趣使然的、简单易用的英雄联盟工具集。支持战绩查询、自动秒选等功能。基于 LCU API。 项目地址: https://gitcode.com/gh_mirrors/le/League-Toolkit League-Toolkit是一…...
避开Verilog数据转换的坑:ASCII码转16进制时,大小写处理你真的做对了吗?
Verilog字符转换实战:如何正确处理ASCII与十六进制的大小写问题 在数字系统设计中,数据格式转换是最基础却又最容易出错的环节之一。最近在review团队一位新成员的UART通信模块代码时,发现一个典型的"大小写陷阱"——当十六进制数据…...
npm新手必看:如何用package.json一键运行本地JS文件(附常见错误排查)
npm新手必看:如何用package.json一键运行本地JS文件(附常见错误排查) 刚接触Node.js生态的开发者,往往会被各种工具和配置文件搞得晕头转向。其中package.json作为项目的"身份证"和"说明书",掌握它…...
