【Leetcode面试常见题目题解】7. 删除链表的倒数第 N 个结点

news2024/11/15 19:32:36

前言

本文是LC第19题:删除链表的倒数第 N 个结点

题目描述

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

限制

链表中结点的数目为 sz
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz

进阶:你能尝试使用一趟扫描实现吗?

示例1:
在这里插入图片描述

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

示例 2:

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

示例 3:

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

解题思路

  • 非递归解决
    先求出链表的长度length,然后就可以找到要删除链表的前一个结点,让他的前一个结点指向要删除结点的下一个结点即可。以示例1为例画个图看一下
    在这里插入图片描述
    首先让 head 指针指向链表的第一个元素。
    在这里插入图片描述
    然后找到要删除节点的前一个节点。
    在这里插入图片描述
    最后让 pre->next 指针指向要删除节点的下一个节点。

  • 双指针解法
    上面是先计算链表的长度,其实不计算链表的长度也是可以,我们可以使用两个指针,一个指针fast先走n步,然后另一个指针slow从头结点开始,找到要删除结点的前一个结点,这样就可以完成结点的删除了。

  • 递归解法
    我们知道获取链表的长度除了上面介绍的一种方式以外,还可以写成递归的方式,比如

//求链表的长度
private int length(ListNode head) {
    if (head == null)
        return 0;
    return length(head.next) + 1;
}
上面计算链表长度的递归其实可以把它看做是从后往前计算,当计算的长度是n的时候就表示遍历到了倒数第n个节点了,这里只要求出倒数第n+1个节点,问题就迎刃而解了

代码

非递归解法——两次遍历

此解法,核心在于找到待删除节点——倒数第N个节点。
如果我们要删除的是第N个节点,那么可以写出的代码是
while (n--) { p = p->next;}
此时 p 节点指向的就是待删除节点。(p节点初始指向 dummynode)

转换一下题目,将倒数第N个节点转换为第M个节点,进行删除。那么M的值是多少?如果知道链表的长度L,那么M = L - N + 1。举个例子:链表 {1,2, 3, 4, 5}, L = 5, N =2, 要删除就是节点4, 而根据公式算 M = 4, 也就是要删除第 4 个节点,节点值为 4。

知道了要删除的节点所在位置(左->右遍历),那么很容易写出如下的代码:

int m = l - n + 1;
while (m--) {
	p = p->next;
}

那么代码链表长度 L 的值如何得来?答案是遍历一遍链表。

因此,这种解法我们需要遍历 2 遍链表,第一遍确定链表长度 L,第二遍找到待删除节点,进行删除。

这版代码简单,读者可以自行编写。
时间复杂度仍然是 O(n)

非递归解法——双指针版

可以将链表分为两部分,假设 L = M + N, 链表分为 M 个节点和 N 个节点。
我们要删除的是倒数第 N 个节点,也就是第 M + 1 个节点,删除第 M + 1个节点,只需要知道第 M 个节点就可以。

如下,将链表分为两部分,后N个节点是没用的,所以我们可以“抹去后N个节点”,然后让链表指针从第一个节点,移动到最后一个节点。
在这里插入图片描述
这里我们将第 M 个节点(第3个节点)的下一个节点看做空,然后将一个指针看做初始指向第 M+1 个节点(待删节点),然后这个指针先向后移动 N 个节点,然后一直向后移动直到遇到第 M 个节点的下一个节点(空节点)。
这个时候,我们是不是就找到了第M个节点?而且回顾下这个过程:真正实际的步骤只有:

指针先向后移动N步,然后向后移动直到节点的next指针为空

在这个描述中,N是已知的,向后移动直到next指针为空则是虚构出来的条件。
因为事实上第 M 个节点的 next 指针指向的节点非空,我们只是为了方便理解如何找到第 M 个节点做出的一种辅助方式。

故,想让一个指针完成这个操作显然是不行的。我们需要再加一个指针,过程就变成了

fast 指针先向后移动 N 步, slow 指针不动
slow 指针和 fast 指针同时向后移动,直到节点的 next 为 NULL

而后,slow 指针指向的节点就是第 M 个节点。

代码如下

/**
 * 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) return nullptr;

        ListNode* dummyNode = new ListNode(-1);
        dummyNode->next = head;
        ListNode* p = dummyNode;
        while(head)
        {
            if(n-- <= 0 && head) p = p->next;
            head = head->next;
        }
        p->next = p->next->next;

        head = dummyNode->next;
        delete dummyNode;
        return head;
    }
};

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

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

相关文章

使用账号激活MATLAB软件

前言 很多学校购买了MATLAB软件的使用权&#xff0c;在校师生只需要使用自己的学校域名的邮箱&#xff0c;注册一个MATLAB账号即可免费使用MATLAB产品&#xff0c;再也不用各种去网上找破解资源了。 账号注册 访问账户注册页面&#xff1a; 创建 MathWorks 帐户然后填写账户信…

三、pyhon基础语法进阶篇(黑马程序猿-python学习记录)

黑马程序猿的python学习视频&#xff1a;https://www.bilibili.com/video/BV1qW4y1a7fU/ 目录 一、文件操作 一、 文件的读取 1. 打开文件open() 2. 读取文件10个字节read(10) 3. 读取文件全部信息read() 4. 读取文件readLines() 5. 读取文件readLine() 6. for循环读取…

【HTML】我用“一行“代码为CSDN博客主页挂上灯笼(附源码)

&#x1f482;作者简介&#xff1a; THUNDER王&#xff0c;一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学会计学专业大二本科在读&#xff0c;同时任汉硕云&#xff08;广东&#xff09;科技有限公司ABAP开发顾问。在学习工作中&#xff0c;我通常使用偏后…

第一章 ArcMap、ArcCatalog、 ArcToolbox基础入门操作

文章目录第一节 ArcMap入门1 界面的基本介绍2 加载数据3 添加图层4 数据表5 内容列表5.1 按绘制顺序5.2 按源5.3 按可见性5.4 按可选性第二节 ArcCatalog入门1 界面和功能介绍2 文件夹连接3 新建数据4 修改字段第三节 ArcToolbox操作入门1 界面基本介绍2 查找工具3 查看帮助4 工…

汇编【王爽】实验8、9

实验8 分析一个奇怪的程序 程序从startstartstart入口处开始执行&#xff0c;一个nop指令占一个字节并表示No operation&#xff0c;此处用了两个nop指令的目的是在sss处预留两个字节的空间&#xff0c;程序执行mov cs:[di], ax之后sss处的两个字节被试图写入jmp short s1&…

【数据结构】二叉树的基本知识

目录前言一、树1、树的相关概念&#xff08;1&#xff09;结点&#xff08;2&#xff09;结点的度&#xff08;3&#xff09;叶结点&#xff08;4&#xff09;分支结点&#xff08;5&#xff09;父亲结点&#xff08;6&#xff09;子节点&#xff08;7&#xff09;树的度&#…

Spring笔记上(基于XML配置)

新年快乐。 文章目录一、Spring概述1. 为什么要用Spring框架&#xff1f;2. Spring介绍二、IOC/DI快速入门1. IOC控制反转2. DI依赖注入三、Bean的配置1. Bean的基础配置2. Bean的别名配置3. Bean的作用范围配置四、Bean的实例化1. 构造方法方式2. 静态工厂方式3. 实例工厂方式…

Java面试题,JVM相关问题

JVM相关问题一 、JDK、JRE、JVM二、内存管理三、GC如何判断对象可以被回收&#xff08;这是JVM的基础&#xff09;一 、JDK、JRE、JVM JDK&#xff1a;Java Development Kit【Java开发工具】&#xff0c;提供给Java开发人员来使用的。JRE&#xff1a;Java Runtime Environment…

Solid Edge 放样使用引导曲线

放样用引导曲线的时候被一个错误提示卡了挺长时间——“选来用作路径或横截面的所有边必须连接在一起”&#xff0c;所以记录一下遇到的问题。基础的操作可以去看帮助文件https://docs.sw.siemens.com/zh-CN/doc/246738425/PL20211001099989437.feature_modeling/feat12c&#…

Sprig框架集成(SSM框架) | Sping+SpringMVC+Mybatis

SSM框架 SSM是spingspringMVCmybatis集成的框架&#xff1a;标准的MVC模式&#xff0c;整个系统划分为表现层&#xff0c;controller层&#xff0c;service层&#xff0c;DAO层四层 Spring&#xff08;业务层&#xff09; Spring就像是整个项目中装配bean的大工厂&#xff0c;在…

MySQL server options

介绍 MySQL安装部署时&#xff0c;经常会关注一些参数是否合理。其实这些参数分为两类型。环境中调整的绝大部分是引擎层方面的。服务层参数&#xff0c;就是mysqld服务启动时的参数&#xff0c;如&#xff1a;datadir&#xff0c;port&#xff0c;socket之类的的&#xff0c;…

多重背包问题——单调队列优化

一、多重背包问题 我们在之前的文章中曾经讲解过多重背包问题&#xff0c;当时我们讲解了两种方法&#xff0c;一种方法就是三重循环&#xff0c;这种方法最为朴素好想。但是这种方法的时间复杂度非常高&#xff0c;后来我们想到了二进制优化的方式。那么今天我们将再介绍一种…

Java实习------Java基础2

基础语法基本数据类型 熟悉Java有哪些数据类型定义&#xff1a;Java语言是强类型语言&#xff0c;对于每一种数据都定义了明确的具体的数据类型&#xff0c;在内存中分配了不同大小的内存空间。Java语言提供了八种基本类型。六种数字类型&#xff08;四个整数型&#xff0c;两个…

18. 循环语句while,for语句的详解

python 中的循环语句只有 for 和 while两种&#xff0c;没有do…while循环&#xff0c;这与c/c是不同的。 1. while循环 (1) 语法格式 while <condition>&#xff1a;...# demo, 使用while循环累加1-100的和。 sum 0 counter 1 while counter < 100:sum counterco…

Java 23种设计模式(4.创建者模式-建造者模式)

代码分析 结构图 代码 public class Product {//产品类,多个部件构成List <String> parts new ArrayList<>();public void Add(String part){parts.add(part);}public void show(){System.out.println("creat parts");for(String part:parts){System…

第十届蓝桥杯省赛 C++ B/C组 - 等差数列

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?spm1011.2415.3001.5343 &#x1f4da;专栏地址&#xff1a;蓝桥杯题解集合 &#x1f4dd;原题地址&#xff1a;等差数列 &#x1f4e3;专栏定位&#xff1a;为想参加蓝桥杯的小伙伴整理常考算法题解&#xff0c;祝大家…

STL分析(九 适配器)

容器适配器&#xff1a;stack&#xff0c;queue stack和queue内含一个deque 函数适配器 binder2nd绑定第二参数 调用的过程中&#xff0c;算法count_if函数读取了迭代器头尾指针后&#xff0c;读取第三个参数为functor object即仿函数。因此在其参数为bind2nd(less< int&g…

LeetCode220123_140、117. 填充每个节点的下一个右侧节点指针 II

给定一个二叉树struct Node {int val;Node *left;Node *right;Node *next;}填充它的每个 next 指针&#xff0c;让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点&#xff0c;则将 next 指针设置为 NULL。初始状态下&#xff0c;所有 next 指针都被设置为 NULL。进阶…

双指针思想,c语言

问题导入 对一个给定的自然数M&#xff0c;求出所有的连续的自然数段&#xff0c;这些连续的自然数段中的全部数之和为M。 例如&#xff1a;1998 1999 2000 2001 2002 10000&#xff0c;所以从1998到2002的一个自然数段为M 10000的一个解。 输入格式 第一行&#xff0…

JQuery总结(三)

jQuery 事件 on可以同时绑定多个事件&#xff0c;并且动态添加的元素也会自动添加事件 自动触发事件&#xff1a; 案例1&#xff1a; <style>div{width: 100px;height: 200px;background-color: violet;transition: all .5s;}.current{width: 200px;height: 100px;ba…