【数据结构】【线性表】【练习】删除链表倒数第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 # 项目配…...
WPF图片处理避坑指南:Image控件Stretch属性的4种模式详解(含效果对比图)
WPF图片处理避坑指南:Image控件Stretch属性的4种模式详解 刚接触WPF开发的工程师们,是否经常遇到图片显示变形、比例失调的困扰?Image控件的Stretch属性看似简单,却藏着不少设计哲学。今天我们就来彻底拆解这个影响图片显示效果的…...
BilibiliDown:你的专属B站视频管家,轻松下载与管理海量内容
BilibiliDown:你的专属B站视频管家,轻松下载与管理海量内容 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader 😳 项目地址: https://gitcode.…...
计算机毕业设计springboot足球俱乐部管理系统 基于SpringBoot的青少年足球培训综合服务平台的设计与实现 基于SpringBoot架构的足球青训营数字化运营系统的设计与实现
计算机毕业设计springboot足球俱乐部管理系统(配套有源码 程序 mysql数据库 论文) 本套源码可以在文本联xi,先看具体系统功能演示视频领取,可分享源码参考。 随着足球运动的全球普及和竞技水平的持续提升,青少年足球培训已成为各国…...
ai辅助c语言开发:让快马智能生成复杂格式文件读写代码
最近在开发一个C语言程序时需要处理自定义数据包格式,正好体验了用AI辅助开发的便捷。这个数据包格式包含包头标识、包体长度和JSON格式的包体数据,需要实现读写功能。下面分享我的实现过程和AI辅助开发的实用技巧。 数据包结构分析 首先明确数据包由三部…...
一种路径优化和速度优化算法实现(仿照百度Apollo方案),只提供代码,有相关的readme文...
一种路径优化和速度优化算法实现(仿照百度Apollo方案),只提供代码,有相关的readme文件。 自动驾驶 ,路径优化,速度优化,pnc。 的代码最近在折腾自动驾驶的路径规划模块,发现实际落地…...
NaViL-9B图文问答教程:支持中英双语提问的跨语言理解能力实测
NaViL-9B图文问答教程:支持中英双语提问的跨语言理解能力实测 1. 认识NaViL-9B NaViL-9B是一款原生多模态大语言模型,由专业研究机构开发。它最吸引人的特点是能够同时理解文字和图片内容,并且支持中文和英文两种语言的提问。想象一下&…...
Mellanox ZTR技术解析:如何通过RTTCC实现零配置高性能RoCE网络
1. 什么是Mellanox ZTR技术? 第一次听说Mellanox ZTR(Zero Touch RoCE)技术时,我的反应和大多数人一样:"这又是什么高大上的黑科技?"但当我真正在金融交易系统里部署它之后,才发现这可…...
车载以太网gPTP时间同步实战:LinuxPTP工具链配置与避坑指南
车载以太网gPTP时间同步实战:从硬件验证到系统调优的全链路指南 当激光雷达的扫描点云与摄像头图像帧的时间戳偏差超过100纳秒,自动驾驶系统的感知模块就可能出现"重影"现象。这正是我们团队在开发L4级自动驾驶平台时遇到的真实挑战——传统时…...
Tracepoint性能优化揭秘:从DECLARE_EVENT_CLASS看Linux内核如何节省50%内存开销
Tracepoint性能优化揭秘:从DECLARE_EVENT_CLASS看Linux内核如何节省50%内存开销 在Linux内核的性能调优领域,Tracepoint机制作为静态跟踪的核心基础设施,其性能表现直接影响着系统监控和故障诊断的效率。本文将深入剖析DECLARE_EVENT_CLASS共…...
高效批处理:一键复制文件/文件夹至当前目录所有子文件夹
1. 为什么需要批量复制文件到子文件夹? 在日常工作中,我经常遇到这样的场景:需要把一个重要文件快速分发到几十甚至上百个子文件夹中。比如给每个项目文件夹添加一份新的规范文档,或者为所有客户目录更新同一份合同模板。手动操作…...
