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

【数据结构】【线性表】【练习】删除链表倒数第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.

分析题目信息

其次观察题目,我们可以获得一些信息:

  1. 该链表为无头结点的单链表,因此删除过程中需要注意第一个结点的删除与其他结点有些许不同。
  2. 该链表删除结点位置是倒着数的,但是单链表是不可逆的;因此在删除时要找到需要删除的位置,必须知道链表总长length,然后遍历链表到length-n个位置,进行删除。
解题思路

根据上述的信息我们解决该问题的大致思路是:

  1. 遍历链表,获取链表总长信息length
  2. 找到要被删除结点的前驱结点length-n
  3. 修改前驱结点的next
  4. 释放要删除的结点空间
代码解析
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个结点在哪?找到末尾结点指针又在最后了,单链表又不可逆,又得从头遍历。好像只能遍历两遍。

        我们重新审视一下这个问题:

  1. 我们必须找到末尾结点,以便确认倒数第n个结点的位置,此时结构体指针在结尾。
  2. 因为单链表不可逆,我要让指针到倒数第n个结点需要重新遍历。
双指针

归根结底就是因为一个指针无法在单链表中倒着走,那么我是不是可以加一个指针呢?让一个指针跟在另一个指针的屁股后面,距离为n。

例如:

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

例如:

        这样的话就只需要遍历一次链表就能实现删除链表的倒数第n个结点;

双指针解题思路
  1. 创建虚拟头结点
  2. 创建前后双指针
  3. 令后指针after指向头结点L,前指针超过后指针n个位置
  4. 前后指针同时向前,直到former到最后一个结点,此时after到达要被删除结点的前驱结点
  5. 修改after的next
  6. 释放空间
代码解析
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个结点

目录 申明 题目 分析题目信息 解题思路 代码解析 技巧解析&#xff1a;创建虚拟头结点 时间复杂度分析 思考&#xff1a;能否只用一趟扫描实现&#xff1f; 双指针 双指针解题思路 代码解析 申明 该题源自力扣题库19&#xff0c;文章内容&#xff08;代码&#xff0c…...

MySQL高级(四):索引

基础概念 什么是索引&#xff1f; 索引是一种数据结构&#xff0c;用于加速查询的过程。它类似于书本的目录&#xff0c;可以快速定位数据行。MySQL 索引主要是基于 B 树&#xff08;也有其他类型如哈希索引、全文索引等&#xff09;来实现的。 为什么使用索引&#xff1f; …...

hhdb数据库介绍(9-21)

计算节点参数说明 checkClusterBeforeDnSwitch 参数说明&#xff1a; PropertyValue参数值checkClusterBeforeDnSwitch是否可见否参数说明集群模式下触发数据节点高可用切换时&#xff0c;是否先判断集群所有成员正常再进行数据节点切换默认值falseReload是否生效是 参数设…...

React中组件通信的几种方式

在构建复杂的React应用时&#xff0c;组件之间的通信是至关重要的。从简单的父子组件通信到跨组件状态同步&#xff0c;不同组件之间的通信方式多种多样。 1. 父子组件通信 父子组件通信是 React 中最基本的通信方式之一。在这种模式下&#xff0c;数据是从父组件通过 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的农产品销售系统的设计与实现

摘 要 随着现代人们的快速发展&#xff0c;农产品销售系统已成为农产品的需求。该平台采用Python技术和django搭建系统框架&#xff0c;后台使用MySQL数据库进行信息管理&#xff1b;通过个人中心、用户管理、商家管理、产品类型管理、农产品管理、系统管理、订单管理等功能&a…...

linux复习5:C prog

编辑 缩排 为了使C源代码更加整洁易读&#xff0c;可以使用一些工具来自动格式化代码&#xff0c;例如cb&#xff08;C程序美化器&#xff09;、bcpp&#xff08;C美化器&#xff09;和indent等。 编译 编译并链接C文件 gcc hello.c -o hello 将 hello.c 编译并链接成可执行文…...

Go语言24小时极速学习教程(三)常见标准库用法

常见标准库 常见标准库即Go语言自带的库&#xff0c;这里的所有包都可以通过import直接引入&#xff0c;如果你觉得实在是不好用&#xff0c;那么请先保证你学会了标准库的基础上&#xff0c;再学一下Gookit&#xff0c;特别是其中的GoUtil&#xff0c;千万不要轻易自己去造轮…...

大数据环境下的高效数据清洗策略

大数据环境下的高效数据清洗策略 在当今这个信息爆炸的时代&#xff0c;大数据已成为企业决策和科学研究不可或缺的重要资源。然而&#xff0c;数据的海量性、多样性和复杂性也给数据处理带来了前所未有的挑战&#xff0c;其中数据清洗是确保数据质量和后续分析准确性的关键步…...

基于SpringBoot3+mybatis搭建的历史上的今天API接口服务 及 Mybatis 应该有个更好的方法来隐藏 Pojo 类中的字段

一、Mybatis有没有比较好的方法隐藏 Pojo 类中的字段 使用 Mybatis 时&#xff0c;为了实现通用的CURD&#xff0c;在定义实体类pojo时&#xff0c;会尽量将能用得上的数据库字段都定义到 pojo中&#xff0c;但是在查询的时候却有不一样的需求。mybatis的文档地址链接&#xff…...

Python 3 字符串

Python 3 字符串 字符串在Python中是一种基本的数据类型&#xff0c;用于存储文本数据。Python中的字符串是不可变的&#xff0c;这意味着一旦创建了一个字符串&#xff0c;就不能更改其内容。字符串可以用单引号&#xff08;&#xff09;、双引号&#xff08;"&#xff…...

Android集成FCM(Firebace Cloud Messaging )

集成FCM官方文档 Firebace主页面 将 Firebase 添加到您的 Android 应用 1、进入Firebace页面&#xff0c;创建自己的项目 2、点击自己创建好的项目&#xff0c;在右侧选择Cloud Messaging 3、点击Android去创建 google-services.json 4、将下载的 google-services.json 文件…...

基于 RBF 神经网络辨识的单神经元 PID 模型参考自适应控制

这是一个基于 RBF 神经网络辨识 和 单神经元 PID 模型参考自适应控制 的系统框图&#xff0c;包含以下主要部分&#xff1a; RBF 神经网络模块&#xff1a;用于对系统进行辨识&#xff0c;输入误差 e(t)e(t)e(t) 和误差变化量 Δe(t)\Delta e(t)Δe(t)&#xff0c;输出与系统特…...

2024年 Web3开发学习路线全指南

Web3是一个包含了很多领域的概念&#xff0c;不讨论币圈和链圈的划分&#xff0c;Web3包括有Defi、NFT、Game等基于区块链的Dapp应用的开发&#xff1b;也有VR、AR等追求视觉沉浸感的XR相关领域的开发&#xff1b;还有基于区块链底层架构或者协议的开发。 这篇文章给出的学习路…...

Ubuntu22.04LTS 部署前后端分离项目

一、安装mysql8.0 1. 安装mysql8.0 # 更新安装包管理工具 sudo apt-get update # 安装 mysql数据库&#xff0c;过程中的选项选择 y sudo apt-get install mysql-server # 启动mysql命令如下 &#xff08;停止mysql的命令为&#xff1a;sudo service mysql stop&#xff0…...

「Mac玩转仓颉内测版23」基础篇3 - 深入理解整数类型

本篇将详细讲解Cangjie中的整数类型&#xff0c;探讨整数的定义、操作、表示范围、进制表示、类型转换及应用场景&#xff0c;帮助开发者在Cangjie中灵活运用整数类型构建程序逻辑。 关键词 有符号整数与无符号整数表示范围与溢出进制表示类型转换字面量与操作 一、整数类型概…...

渗透测试导学

渗透测试导学 渗透测试概念 渗透测试是干什么&#xff1f; 渗透测试的定义和目的&#xff1a;渗透测试是一种通过模拟恶意黑客的攻击方法&#xff0c;来评估计算机网络系统安全性能的评估方法。它的目的是通过识别安全问题&#xff0c;帮助了解当前的安全状况&#xff0c;从而…...

Django实现智能问答助手-基础配置

设置 Django 项目、创建应用、定义模型和视图、实现问答逻辑&#xff0c;并设计用户界面。下面是一步一步的简要说明&#xff1a; 目录&#xff1a; QnAAssistant/ # 项目目录 │ ├── QnAAssistant/ # 项目文件夹 │ ├── init.py # 空文件 │ ├── settings.py # 项目配…...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文&#xff1f; 多租户隔离&#xff1a;自动为接入设备追加租户前缀&#xff0c;后端按 ClientID 拆分队列。零代码鉴权&#xff1a;将入站用户名替换为 OAuth Access-Token&#xff0c;后端 Broker 统一校验。灰度发布&#xff1a;根据 IP/地理位写…...

2021-03-15 iview一些问题

1.iview 在使用tree组件时&#xff0c;发现没有set类的方法&#xff0c;只有get&#xff0c;那么要改变tree值&#xff0c;只能遍历treeData&#xff0c;递归修改treeData的checked&#xff0c;发现无法更改&#xff0c;原因在于check模式下&#xff0c;子元素的勾选状态跟父节…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好&#xff0c;总是藏在那些你咬牙坚持的日子里。 硬件&#xff1a;OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写&#xff0c;"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

今日科技热点速览

&#x1f525; 今日科技热点速览 &#x1f3ae; 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售&#xff0c;主打更强图形性能与沉浸式体验&#xff0c;支持多模态交互&#xff0c;受到全球玩家热捧 。 &#x1f916; 人工智能持续突破 DeepSeek-R1&…...

重启Eureka集群中的节点,对已经注册的服务有什么影响

先看答案&#xff0c;如果正确地操作&#xff0c;重启Eureka集群中的节点&#xff0c;对已经注册的服务影响非常小&#xff0c;甚至可以做到无感知。 但如果操作不当&#xff0c;可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...

C++.OpenGL (20/64)混合(Blending)

混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...

uniapp 字符包含的相关方法

在uniapp中&#xff0c;如果你想检查一个字符串是否包含另一个子字符串&#xff0c;你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的&#xff0c;但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...

4. TypeScript 类型推断与类型组合

一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式&#xff0c;自动确定它们的类型。 这一特性减少了显式类型注解的需要&#xff0c;在保持类型安全的同时简化了代码。通过分析上下文和初始值&#xff0c;TypeSc…...