【LeetCode】返回链表的中间结点、删除链表的倒数第 N 个结点

主页:HABUO🍁主页:HABUO

🌜钱塘江上潮信来,今日方知我是我🌛


1.返回链表的中间结点

题目:给你单链表的头结点 head ,请你找出并返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。

示例:

输入:head = [1,2,3,4,5]       输出:[3,4,5]       解释:链表只有一个中间结点,值为 3 。

输入:head = [1,2,3,4,5,6]    输出:[4,5,6]       解释:该链表有两个中间结点,值分别为 3 和 4 ,返回第二个结点。

分析:我们要找到中间节点,是不是有两种可能性,节点数为奇数和偶数两种,奇数的话很简单就是中间的节点,偶数是不是中间就有两个节点,根据题中意思,我们需要返回的是这两个节点中的第二个节点,我们的方法是采用两个伪指针的方法,什么意思呢?就是说,两个伪指针刚开始都指向我们的头指针,走的过程中,快指针走两步,慢指针走一步,当快指针走完整个链表的时候,它们的差是不是就是整个链表的一半,这就是我们的思路,具体可看下图:

当然这里快指针走向最后的时候有些细节需要注意,奇数的话当slow走向中间节点的时候,fast刚好走向最后一个节点,也即是fast->next = NULL,奇数情况见下图,但是这个偶数情况fast就跑到链表之外,如果再进行访问就会造成对NULL访问的错误,因此处理方法见下:

fast != NULL && fast->next != NULL

综上,我们的总体代码如下:

struct ListNode* middleNode(struct ListNode* head) {struct ListNode* slow = head;struct ListNode* fast = head;while(fast != NULL && fast->next != NULL){slow = slow->next;fast = fast->next->next;}return slow;
}

2.删除链表的倒数第 N 个结点

题目:给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

示例:

输入:head = [1,2,3,4,5], n = 2 输出:[1,2,3,5]

输入:head = [1], n = 1 输出:[]

输入:head = [1,2], n = 1 输出:[1]

分析:这个题我们乍一看是不是上一个题的进阶版啊🤭,没错,这就是上一个题的通用版,会了这个题是不是,无论它让找第几个节点,我们都能找到😁。现在就让我们领略这道题的神奇,我将以两种方法去讲解,第二种方法也是第一种方法的进阶。根据上一题的思路,我们仍然采用双指针去找到倒数第n个节点,我们该怎么想呢?上一题因为它们走的步差到最后刚好一半,那这道题是不是也是这种思路呢?没错就是这种思路不过和上道题不同的是这次我们让它一开始就差距n步,那fast走到最后,因为差了n步,slow是不是就恰好在倒数第n个节点的位置,对就是这种思路🌞。因为这道题需要我们去删除,因此我们还应该需要一个伪指针指向slow前一个节点。整体思路见下:

这里需要注意虽然n=2,即是让我们去删除倒数第二个节点,但是倒数第一个和第二个之间是不是就一步,因此我们只需要让fast先走一步即可,所以总体思想见下:

struct ListNode* fast = head;
struct ListNode* slow = head;
struct ListNode* prev = NULL;
while (--n)//fast与slow相差的步数
{fast = fast->next;
}
while (fast->next != NULL)
{fast = fast->next;prev = slow;slow = slow->next;
}
prev->next = slow->next;
free(slow);
slow = NULL;
return head;

实现了上面的代码就大功告成了吗?其实这只是最正常的情况,只是我们让fast和slow动了起来,还有许多的细节没考虑到,例如:如果只有一个节点怎么办?我们要删最后一个节点怎么办?我们要删大于一个节点的头节点怎么办?好不容易有了思路,怎么还有这么多细节要考虑,是不是有点烦🫥,我劝你别烦,我们来一步一步的分析:

第一个问题:如果只有一个节点怎么办?如下所示:

如果用上面的代码两个while循环都没有进去,下面紧接着就是prev->next,立马就出现对NULL解引用的错误,还有下面 free(slow),空间还给了内存,我们的head和fast成了野指针了,是不是都是问题,所以们需要另外考虑一下这个情况,解决如下:

head = slow->next;
free(slow);
slow = NULL;
fast = NULL;
return head;

第二个问题:如果要删最后一个节点怎么办?如下所示:

这个问题只需要将我们最正常情况加上一句fast = NULL,为了防止fast成为野指针

至于第三个问题如果我们要删大于一个节点的头节点,其实在上述头节点的删除过程中已经解决,因为上述代码的妙处就在于head = slow->next在free(slow)之前,如果在它之后,是不是就要两种情况,因为slow后面又可能为NULL又可能不为NULL。因此头尾解决好,就剩下正常思路我们一开始就解决的了,所以这个问题就已经迎刃而解了,总体代码见下:

struct ListNode* removeNthFromEnd(struct ListNode* head, int n) {struct ListNode* fast = head;struct ListNode* slow = head;struct ListNode* prev = NULL;while (--n){fast = fast->next;}while (fast->next != NULL){fast = fast->next;prev = slow;slow = slow->next;}if (prev == NULL)//头删{head = slow->next;free(slow);slow = NULL;fast = NULL;return head;}else//正常删+尾删{prev->next = slow->next;free(slow);slow = NULL;fast = NULL;return head;}
}

方法二:带有哨兵位的双指针法 

分析:上面我们看到又是这种细节需要考虑,又是那种细节要考虑,是不是挺令人讨嫌😒,因此我们设置一个哨兵位节点放置在头节点处,那prev就不可能为NULL,这还考虑prev为不为NULL干什么,让它一边去!思路见下:

此时无论怎么样,prev都不可能为NULL,想怎么访问就怎么访问,上面的方法麻烦就麻烦在prev有两种可能性,但这个方法需要注意的是我们返回的是head->next,还需要注意进入循环之前把prev和head安排好,具体见下:

struct ListNode* prev = (struct ListNode*)malloc(sizeof(struct ListNode));
prev->next = head;
head = prev;
return head->next;

其它和我们上个方法正常情况是一样的。总体代码见下:

struct ListNode* removeNthFromEnd(struct ListNode* head, int n) {struct ListNode* fast = head;struct ListNode* slow = head;struct ListNode* prev = (struct ListNode*)malloc(sizeof(struct ListNode));prev->next = head;head = prev;while (--n){fast = fast->next;}while (fast->next != NULL){fast = fast->next;prev = slow;slow = slow->next;}prev->next = slow->next;free(slow);slow = NULL;return head->next;
}

🍁时间可以伸缩和折叠,唯独不能倒退🍁

🌟不要温和地走进那个良夜🌟

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/6516.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Netty篇(学习前言)

目录 一、为什么使用Netty 1. Netty编程相比NIO编程的优势 2. Netty 相比其它网络应用框架的优势 二、让我们走进Netty 1. 简介 2. 设计目标 3. 主要特点 4. Netty的作者 5. Netty 的地位 6. Netty 的优势 五、Netty版本说明 六、Netty架构设计 1. 线程模型基本介绍…

Ceph 学习指南 集群部署【 cephadm 】

文章目录 引言初识 Server SANServer SAN 和传统存储对比 Ceph 概述Ceph 的架构设计Ceph 的特点Ceph 块存储Ceph 文件系统Ceph 对象存储Ceph 介绍 Ceph 集群部署配置 aliyun 源配置时间同步配置 hosts 文件安装 docker配置免密登录ceph 集群部署ceph1 配置安装 python3安装 cep…

Linux篇(常见入门命令)

目录 一、开启终端 二、Linux命令格式 1. 什么是Linux 的命令? 三、Linux下的命令补全 四、切换用户 五、uname:查看操作系统信息 六、ls:查看目录下文件 1. 用法一 2. 用法二 3. 用法三 七、pwd:显示当前路径 八、cd&…

全面解析:网络协议及其应用

💓 博客主页:瑕疵的CSDN主页 📝 Gitee主页:瑕疵的gitee主页 ⏩ 文章专栏:《热点资讯》 # 全面解析:网络协议及其应用 文章目录 网络协议概述定义发展历程主要优势 主要网络协议应用层协议传输层协议网络层…

02- 模块化编程-006 ADC0808数码显示对比

1、ADC0808 芯片介绍 ADC0808是一款集成的CMOS设备,包含8位模拟至数字转换器、8通道多路复用器和与微处理器兼容的控制逻辑。8位A/D转换器采用逐次逼近作为转换技术。转换器特点包括高阻抗斩波稳定比较器、256R电压分压器、模拟开关树和逐次逼近寄存器。8通道多路复…

【自动化测试】APP UI 自动化(安卓)-本地环境搭建

一、软件准备及版本介绍 软件版本JAVA-SDK1.8.0_181 python 3.10.10 Android SDK Tools 下最新版本即可,无特殊要求 PyCharm 2023.3.5(下最新版本即可,无特殊要求) 二、安装步骤及环境变量配置 2.1 Java安装及配置 1&am…

leetcode912.排序数组的题解

题目描述: 题目要求在不使用任何内置函数的情况下解决问题,时间复杂度为 O(nlog(n))。 笔者使用了快速排序,但是直接使用最原始的快速排序,有些特殊的测试用例会超时。 1)如果数组本身基本有序,则使用原始…

安装Blender并使用

前言 该系列记录了如何用Blenderpro来构建自己的场景数据集,从环境搭建到后期构建数据集的整个流程 本文章是第一部分,BlenderPrc2的安装以及环境配置 部分参考https://blog.csdn.net/weixin_49521551/article/details/121573334 官方文档https://dlr…

json-server的使用(根据json数据一键生成接口)

一.使用目的 在前端开发初期,后端 API 可能还未完成,json-server 可以快速创建模拟的 RESTful API,帮助前端开发者进行开发和测试。 二.安装 npm install json-server //局部安装npm i json-server -g //全局安装 三.使用教程 1.准备一…

MySQL详细安装教程

一、从MySQL官网安装 可以翻译成中文看起来就舒服多了 下载并打开安装包,能看到版本是8.0.36,双击运行或者右键选择打开,打开后是一个安装向导,这个安装向导会先帮我们安装一个 mysql-installer 的程序,再通过该程序安…

qt QErrorMessage详解

1、概述 QErrorMessage是Qt框架中用于显示错误消息的一个对话框类。它提供了一个简单的模态对话框,用于向用户显示错误或警告消息。QErrorMessage通常用于应用程序中,当需要向用户报告错误但不希望中断当前操作时。它提供了一个标准的错误消息界面&…

Vue3安装、创建到使用

vue安装 npm install vuenext # 全局安装 vue-cli npm install -g vue/cli #更新插件 项目中运行 vue upgrade --nextvue create 命令 vue create [options] <app-name> options 选项可以是&#xff1a; -p, --preset <presetName>&#xff1a; 忽略提示符并使用已…

Linux 下执行定时任务之 Systemd Timers

不知道 ECS 因为什么缘故&#xff0c;上面安装的 MySQL 服务老是不定期挂掉&#xff0c;本来想通过 Linux 得 Cron 配置个半小时的定时检测任务&#xff0c;结果一直没有执行&#xff0c;因此又尝试使用了 Systemd Timers 进行了重新配置&#xff0c;简要做个记录。 Systemd Ti…

计算机网络:网络层 —— IP 多播技术

文章目录 基本概念IP多播地址和多播组 IP多播的类型硬件多播将IPv4多播地址映射为多播MAC地址 基本概念 多播&#xff08;Multicast&#xff0c;也称为组播&#xff09;是一种实现“一对多”通信的技术&#xff0c;允许一台或多台主机&#xff08;多播源&#xff09;发送单一数…

OuteTTS:基于纯语言建模的开源文本到语音合成项目,支持语音克隆等多种语音合成任务

❤️ 如果你也关注大模型与 AI 的发展现状&#xff0c;且对大模型应用开发非常感兴趣&#xff0c;我会快速跟你分享最新的感兴趣的 AI 应用和热点信息&#xff0c;也会不定期分享自己的想法和开源实例&#xff0c;欢迎关注我哦&#xff01; &#x1f966; 微信公众号&#xff…

C语言 | Leetcode C语言题解之第540题有序数组中的单一元素

题目&#xff1a; 题解&#xff1a; int singleNonDuplicate(int* nums, int numsSize) {int low 0, high numsSize - 1;while (low < high) {int mid (high - low) / 2 low;mid - mid & 1;if (nums[mid] nums[mid 1]) {low mid 2;} else {high mid;}}return …

【学习笔记】SAP ABAP——数据类型

SAP ABAP——数据类型 SAP模块介绍数据类型内涵数据类型分类预定义数据类型数据字典数据类型用户自定义数据类型 SAP模块介绍 模块模块名称FI财务会计CO管理会计SD销售分销MM物料管理PM工厂维护HR人力资源PS项目管理BW数据仓库BC系统相关PP生产制造 数据类型内涵 ​ 数据类型…

国产服务器平台离线部署k8s和kubesphere(含离线部署新方式)

"信创&#xff1a;鲲鹏麒麟&#xff0c;ARM64架构&#xff0c;实现K8s和Kubesphere的离线部署&#xff0c;全新方式助力企业高效运维。" 本文将深入探讨如何借助鲲鹏CPU(arm64)和操作系统Kylin V10 SP2/SP3,通过KubeKey制作KubeSphere与Kubernetes的离线安装包&#…

SpringBoot在线教育系统:技术与实践

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

初始JavaEE篇——多线程(7):定时器、CAS

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a;JavaEE 目录 定时器的使用 定时器的原理 模拟实现定时器 CAS 介绍 CAS的应用场景 解析 AtomicInteger 类 实现自旋锁 CAS的缺陷…