【数据结构】【线性表】【练习】删除链表倒数第n个结点
目录
申明
题目
分析题目信息
解题思路
代码解析
技巧解析:创建虚拟头结点
时间复杂度分析
思考:能否只用一趟扫描实现?
双指针
双指针解题思路
代码解析
申明
该题源自力扣题库19,文章内容(代码,图表等)均原创,侵删!
题目
给你一个链表,删除链表的倒数第n个结点,并返回链表!
示例:n=2,删除倒数第二个链表。

输入:[1,2,3,4,5]
输出:[1,2,3,5]
链表结构体:
struct ListNode {int val;struct ListNode *next;
};
题目相关信息到此为止,我们需要分析一下题目。
回顾链表结点的删除,最重要的步骤是:找到要被删除的结点的前驱结点,修改其next指向要被删除结点的后继结点。例如例题中的要被删除结点为4,因此要将其前驱结点3指向其后继结点5.
分析题目信息
其次观察题目,我们可以获得一些信息:
- 该链表为无头结点的单链表,因此删除过程中需要注意第一个结点的删除与其他结点有些许不同。
- 该链表删除结点位置是倒着数的,但是单链表是不可逆的;因此在删除时要找到需要删除的位置,必须知道链表总长length,然后遍历链表到length-n个位置,进行删除。
解题思路
根据上述的信息我们解决该问题的大致思路是:
- 遍历链表,获取链表总长信息length
- 找到要被删除结点的前驱结点length-n
- 修改前驱结点的next
- 释放要删除的结点空间
代码解析
struct ListNode* removeNthFromEnd(struct ListNode* head, int n) {int length = 0;//初始化链表总长为0/*1.遍历链表,获取链表总长*/struct ListNode* p ;//p表示当前结点p = head;while (p!= NULL) {++length;p = p->next;}/*为了方便删除操作,我们创建一个虚拟头结点*/struct ListNode dummy;dummy.next = head;struct ListNode* prev = &dummy;//prer表示当前结点/*2.遍历链表找到要删除结点的前驱结点*/for (int i=0;i < length - n;i++) {prev = prev->next;}/*3.修改前驱结点的next*/struct ListNode* s = prev->next;//s暂存要被删除结点prev->next = s->next;//修改要被删除结点的前驱结点的next指针/*4.释放要删除的结点空间*/free(s);//释放内存空间return dummy.next;//返回链表头结点
}
技巧解析:创建虚拟头结点
我们再来观察一下是否有头结点的链表的区别:
有头结点的链表:

L为头结点,它和其他结点没有本质上没有区别,但其本身不存储数据,它的next指针指向第一个结点,从第一个结点开始才算链表的真正数据主体。
无头结点的链表:

这里我们需要注意,这里的L不是结点,只是一个指针,它没有next,而是直接指向第一个结点。
回顾一下链表的插入和删除,非常重要的一个步骤就是:修改被操作结点的前驱结点的next。
而我们在对无头结点链表的第一个结点进行操作时,找不到其前驱结点,因此需要对其特殊处理,其处理方式和其他结点会有略微差距,因此代码上较为繁杂。而有头结点的存在则不需要考虑第一个结点的问题,相对来说操作更加方便,逻辑更加清晰统一。
为了使代码操作更具有统一性,我们可以在函数内部创建一个虚拟头结点,将虚拟头指针的next指向原链表的第一个结点,暂时供链表使用。在使用完成后,注意输出时的结点要从虚拟头结点的next结点,摒弃头结点,保持输入输出链表结构的一致性。
时间复杂度分析
时间复杂度分析当数据量足够大时,影响其时间的往往是最深层的代码,相对而言其它层的可以忽略不记。因此上述方法的时间复杂度主要来自于两个循环语句,while和for。第一个while用于遍历链表获得链表长度数据length,for用于找到链表中要被删除结点的前驱结点(length-n)。
- 最好情况是n=length,要删除结点为第一个结点,时间复杂度为O(1).
- 最坏情况为n=1,要删除结点为最后一个结点,时间复杂度为O(n).
- 平均情况时间复杂度为O(n)
思考:能否只用一趟扫描实现?
不知道你们是否感觉到两次遍历很麻烦,但不知道链表长度我又不知道倒数第n个在哪,就很矛盾。单链表又是不可逆的,不能从末尾结点去遍历,这可怎么办呢?到这里就陷入一个难题,不找到末尾结点就找不到倒数第n个结点在哪?找到末尾结点指针又在最后了,单链表又不可逆,又得从头遍历。好像只能遍历两遍。
我们重新审视一下这个问题:
- 我们必须找到末尾结点,以便确认倒数第n个结点的位置,此时结构体指针在结尾。
- 因为单链表不可逆,我要让指针到倒数第n个结点需要重新遍历。
双指针
归根结底就是因为一个指针无法在单链表中倒着走,那么我是不是可以加一个指针呢?让一个指针跟在另一个指针的屁股后面,距离为n。
例如:

当前面那个指针指向最后一个结点时,后面那个指针刚好在倒数第n个结点的前驱结点那里。
例如:

这样的话就只需要遍历一次链表就能实现删除链表的倒数第n个结点;
双指针解题思路
- 创建虚拟头结点
- 创建前后双指针
- 令后指针after指向头结点L,前指针超过后指针n个位置
- 前后指针同时向前,直到former到最后一个结点,此时after到达要被删除结点的前驱结点
- 修改after的next
- 释放空间
代码解析
struct ListNode* removeNthFromEnd(struct ListNode* head, int n) {/*1.创建虚拟头结点*/struct ListNode dummy;dummy.next = head;/*2.创建前后双指针*/struct ListNode* former;struct ListNode* after;/*3.前后双指针位置初始化*/former=&dummy;for(int i=0;i<n;i++){former=former->next;}after=&dummy;/*4.遍历链表直到former到达末尾结点*/while(former->next!=NULL){after=after->next;former=former->next;}/*5.修改after的next*/struct ListNode* s=after->next;after->next=s->next;/*6.释放空间*/free(s);return dummy.next;
}
好的各位,这个题目暂时就讲到这里,如果大家有新的题目或者有新的思路,欢迎各位大佬评论或私信。
相关文章:
【数据结构】【线性表】【练习】删除链表倒数第n个结点
目录 申明 题目 分析题目信息 解题思路 代码解析 技巧解析:创建虚拟头结点 时间复杂度分析 思考:能否只用一趟扫描实现? 双指针 双指针解题思路 代码解析 申明 该题源自力扣题库19,文章内容(代码,…...
MySQL高级(四):索引
基础概念 什么是索引? 索引是一种数据结构,用于加速查询的过程。它类似于书本的目录,可以快速定位数据行。MySQL 索引主要是基于 B 树(也有其他类型如哈希索引、全文索引等)来实现的。 为什么使用索引? …...
hhdb数据库介绍(9-21)
计算节点参数说明 checkClusterBeforeDnSwitch 参数说明: PropertyValue参数值checkClusterBeforeDnSwitch是否可见否参数说明集群模式下触发数据节点高可用切换时,是否先判断集群所有成员正常再进行数据节点切换默认值falseReload是否生效是 参数设…...
React中组件通信的几种方式
在构建复杂的React应用时,组件之间的通信是至关重要的。从简单的父子组件通信到跨组件状态同步,不同组件之间的通信方式多种多样。 1. 父子组件通信 父子组件通信是 React 中最基本的通信方式之一。在这种模式下,数据是从父组件通过 props …...
python脚本实现csv中百度经纬度转84经纬度
数据准备 csv文件,带百度经纬度字段:bd09_x,bd09_y 目的 将百度经纬度转换为84经纬度,并在csv文件中添加两个字段:84_x,84_y python脚本 from ChangeCoordinate import ChangeCoordimport pandas as pd import numpy as npcoord = ChangeCoord()def bd09_to_wgs84...
syslog udp配置笔记
要将 /var/log/ 目录下的日志信息通过 UDP 发送到远程服务器,可以使用 rsyslog 的配置来实现。以下是详细步骤: 步骤 1:确保 rsyslog 已安装 如果 rsyslog 没有安装,请使用以下命令进行安装: 在 CentOS/RHEL: sudo yum install rsyslog在 Ubuntu/Debian: sudo apt-get i…...
Linux环境开启MongoDB的安全认证
文章目录 1. MongoDB安全认证简介1.1 访问控制1.2 角色1.3 权限 2. MongoDB中的常见角色3. MongoDB Shell3.1 下载MongoDB Shell3.2 通过MongoDB Shell连接MongoDB 4. 创建管理员用户5. 为具体的数据库创建用户6. 开启权限认证7. 重启MongoDB服务8. 连接MongoDB9. MongoDB数据库…...
django基于Python的农产品销售系统的设计与实现
摘 要 随着现代人们的快速发展,农产品销售系统已成为农产品的需求。该平台采用Python技术和django搭建系统框架,后台使用MySQL数据库进行信息管理;通过个人中心、用户管理、商家管理、产品类型管理、农产品管理、系统管理、订单管理等功能&a…...
linux复习5:C prog
编辑 缩排 为了使C源代码更加整洁易读,可以使用一些工具来自动格式化代码,例如cb(C程序美化器)、bcpp(C美化器)和indent等。 编译 编译并链接C文件 gcc hello.c -o hello 将 hello.c 编译并链接成可执行文…...
Go语言24小时极速学习教程(三)常见标准库用法
常见标准库 常见标准库即Go语言自带的库,这里的所有包都可以通过import直接引入,如果你觉得实在是不好用,那么请先保证你学会了标准库的基础上,再学一下Gookit,特别是其中的GoUtil,千万不要轻易自己去造轮…...
大数据环境下的高效数据清洗策略
大数据环境下的高效数据清洗策略 在当今这个信息爆炸的时代,大数据已成为企业决策和科学研究不可或缺的重要资源。然而,数据的海量性、多样性和复杂性也给数据处理带来了前所未有的挑战,其中数据清洗是确保数据质量和后续分析准确性的关键步…...
基于SpringBoot3+mybatis搭建的历史上的今天API接口服务 及 Mybatis 应该有个更好的方法来隐藏 Pojo 类中的字段
一、Mybatis有没有比较好的方法隐藏 Pojo 类中的字段 使用 Mybatis 时,为了实现通用的CURD,在定义实体类pojo时,会尽量将能用得上的数据库字段都定义到 pojo中,但是在查询的时候却有不一样的需求。mybatis的文档地址链接ÿ…...
Python 3 字符串
Python 3 字符串 字符串在Python中是一种基本的数据类型,用于存储文本数据。Python中的字符串是不可变的,这意味着一旦创建了一个字符串,就不能更改其内容。字符串可以用单引号()、双引号("ÿ…...
Android集成FCM(Firebace Cloud Messaging )
集成FCM官方文档 Firebace主页面 将 Firebase 添加到您的 Android 应用 1、进入Firebace页面,创建自己的项目 2、点击自己创建好的项目,在右侧选择Cloud Messaging 3、点击Android去创建 google-services.json 4、将下载的 google-services.json 文件…...
基于 RBF 神经网络辨识的单神经元 PID 模型参考自适应控制
这是一个基于 RBF 神经网络辨识 和 单神经元 PID 模型参考自适应控制 的系统框图,包含以下主要部分: RBF 神经网络模块:用于对系统进行辨识,输入误差 e(t)e(t)e(t) 和误差变化量 Δe(t)\Delta e(t)Δe(t),输出与系统特…...
2024年 Web3开发学习路线全指南
Web3是一个包含了很多领域的概念,不讨论币圈和链圈的划分,Web3包括有Defi、NFT、Game等基于区块链的Dapp应用的开发;也有VR、AR等追求视觉沉浸感的XR相关领域的开发;还有基于区块链底层架构或者协议的开发。 这篇文章给出的学习路…...
Ubuntu22.04LTS 部署前后端分离项目
一、安装mysql8.0 1. 安装mysql8.0 # 更新安装包管理工具 sudo apt-get update # 安装 mysql数据库,过程中的选项选择 y sudo apt-get install mysql-server # 启动mysql命令如下 (停止mysql的命令为:sudo service mysql stop࿰…...
「Mac玩转仓颉内测版23」基础篇3 - 深入理解整数类型
本篇将详细讲解Cangjie中的整数类型,探讨整数的定义、操作、表示范围、进制表示、类型转换及应用场景,帮助开发者在Cangjie中灵活运用整数类型构建程序逻辑。 关键词 有符号整数与无符号整数表示范围与溢出进制表示类型转换字面量与操作 一、整数类型概…...
渗透测试导学
渗透测试导学 渗透测试概念 渗透测试是干什么? 渗透测试的定义和目的:渗透测试是一种通过模拟恶意黑客的攻击方法,来评估计算机网络系统安全性能的评估方法。它的目的是通过识别安全问题,帮助了解当前的安全状况,从而…...
Django实现智能问答助手-基础配置
设置 Django 项目、创建应用、定义模型和视图、实现问答逻辑,并设计用户界面。下面是一步一步的简要说明: 目录: QnAAssistant/ # 项目目录 │ ├── QnAAssistant/ # 项目文件夹 │ ├── init.py # 空文件 │ ├── settings.py # 项目配…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...
【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...
Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...
在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
