力扣题目解析--删除链表的倒数第n个节点

news2024/11/25 14:32:49

题目

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

示例 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]

提示:

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

代码展示

/**
 * 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) {
        ListNode *dummy=new ListNode(0);
        dummy->next=head;
        ListNode *current=dummy;
        ListNode *fast=dummy;
        ListNode *slow=dummy;
        for(int i=0;i<n;i++){
            if(fast->next==nullptr){
                delete dummy;
                return head;
            }
            fast=fast->next;
        }
        while (fast->next!=nullptr){
            fast=fast->next;
            slow=slow->next;
        }
        ListNode* toDelete =slow->next;
        slow->next=slow->next->next;
        delete toDelete;

        ListNode* newHead=dummy->next;
        delete dummy;
        return newHead;
    }
};

写者心得

要想搞明白这个题就必须得先看得懂题目在开头给的注释,那里面有关于对于列表是怎么设置的,写者就是在先去搞明白他是怎样设置列表之后再写代码的。这结构体设置的并不难,但其中有一个点是我搞错了的,val它其实是链表中的值,而我一直把它当做链表的一个元素来看待,所以造成了一些错误。代码有一些写的比较好的地方:

1.虚拟头节点

对比分析

  1. 删除头节点

    • 没有虚拟头节点:需要单独处理头节点的删除情况,代码复杂度增加。
    • 有虚拟头节点:删除头节点和其他节点的操作一致,代码简洁。
  2. 代码简洁性

    • 没有虚拟头节点:需要更多的条件判断,代码冗长。
    • 有虚拟头节点:代码结构更清晰,易于理解和维护。

虚拟头节点在链表中是非常常用的,其实它的作用很简单,就是当你在处理列表中节点的时候,有可能会处理到头节点的情况,正是因为我们把这个头节点虚拟化了,所以就不需要考虑这个问题了,这样子可以省去我们许多关于头节点的条件设置

2.双指针

但其实这个双指针和我们在前面所用到的双指针是完全不同的两个东西,过去的双指针是为了遍历数组 ,而这个双指针则是为了寻找节点,其实这个思路很像是双循环,一个负责遍历,另一个则负责删除,所以一个指针设为快指针,另一个指针设为慢指针,这样就可以在链表之中寻找节点,我想这个方法应该和双循环暴力破解有异曲同工之处,而在接下来我们处理链表问题的时候,会经常用到这样子的思路和这样的做法。

代码解析

/**
 * 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) {}
 * };
 */

这部分定义了一个单链表节点的结构体 ListNode,包含三个构造函数:

  • 默认构造函数:ListNode() : val(0), next(nullptr) {}
  • 带一个参数的构造函数:ListNode(int x) : val(x), next(nullptr) {}
  • 带两个参数的构造函数:ListNode(int x, ListNode *next) : val(x), next(next) {}

创建虚拟头节点

        ListNode *dummy = new ListNode(0);
        dummy->next = head;
  • 创建一个虚拟头节点 dummy,其值为 0next 指向原链表的头节点 head
  • 虚拟头节点的作用是简化边界条件的处理,特别是删除头节点的情况。

初始化指针

        ListNode *current = dummy;
        ListNode *fast = dummy;
        ListNode *slow = dummy;
  • 初始化三个指针 currentfast 和 slow,都指向虚拟头节点 dummy

快指针先走 n 步

        for (int i = 0; i < n; i++) {
            if (fast->next == nullptr) {
                delete dummy;
                return head;
            }
            fast = fast->next;
        }
  • 使用一个 for 循环让快指针 fast 先向前移动 nn 步。
  • 在每次移动前,检查 fast->next 是否为 nullptr,如果是,说明链表长度小于 nn,直接返回原链表。
  • 如果链表长度大于等于 nn,继续移动快指针。

同步移动快指针和慢指针

        while (fast->next != nullptr) {
            fast = fast->next;
            slow = slow->next;
        }
  • 使用一个 while 循环同步移动快指针 fast 和慢指针 slow,直到快指针到达链表的末尾。
  • 当快指针到达链表末尾时,慢指针正好指向倒数第 nn 个节点的前一个节点。

删除慢指针的下一个节点

        ListNode* toDelete = slow->next;
        slow->next = slow->next->next;
        delete toDelete;
  • 记录要删除的节点 toDelete,即 slow->next
  • 将慢指针的 next 指针指向要删除节点的下一个节点,从而跳过要删除的节点。
  • 释放要删除节点的内存。

返回新的头节点

        ListNode* newHead = dummy->next;
        delete dummy;
        return newHead;
    }
};
  • 返回新的头节点 newHead,即 dummy->next
  • 释放虚拟头节点的内存。
  • 返回新的头节点。

总结

通过使用虚拟头节点和双指针法,我们可以有效地删除链表中的倒数第 nn 个节点。虚拟头节点简化了边界条件的处理,双指针法确保了我们能够准确地找到要删除的节点的位置。

 

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

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

相关文章

web实操5——http数据详解,request对象功能

http请求数据 现在我们浏览器f12的那些是浏览器给http格式数据整理之后便于我们阅读的。 原始的http格式信息&#xff1a; 就是按照一定格式和符号的字符串&#xff1a; 请求行&#xff1a;格式如下图 请求头&#xff1a;一个个key&#xff0c;value数据&#xff0c;用,分割…

大语言模型LLMs在医学领域的最新进展总结

我是娜姐 迪娜学姐 &#xff0c;一个SCI医学期刊编辑&#xff0c;探索用AI工具提效论文写作和发表。 相比其他学科&#xff0c;医学AI&#xff0c;是发表学术成果最多的领域。 医学数据的多样性和复杂性&#xff08;包括文本、图像、基因组数据等&#xff09;&#xff0c;使得…

React的概念以及发展前景如何?

React是一个由Facebook开发的用于构建用户界面的的开源JavaScript库&#xff0c;它主要用于构建大型、动态的Web应用程序。React的主要特点是使用VirtualDOM&#xff08;虚拟DOM&#xff09;来优化性能&#xff0c;并使用声明式的编程方式来编写UI。 React的主要概念包括&#…

计算机课程管理:Spring Boot与工程认证的协同

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

【Linux系列】命令行中的文本处理:从中划线到下划线与大写转换

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

不一样的CSS(一)

目录 前言&#xff1a; 一、规则图形 1.介绍&#xff1a; 2.正方形与长方形&#xff08;实心与空心&#xff09; 2.1正方形&#xff1a; 2.2长方形 3.圆形与椭圆形&#xff08;空心与实心&#xff09; 3.1圆形与椭圆形 4.不同方向的三角形 4.1原理 4.2边框属性 5.四…

HPM6750EVK2开发板程序烧录测试

对于HPM6750EVK2开发板&#xff0c;官方板子上没有板载调试器&#xff0c;从淘宝上购买了一个&#xff0c;据说配套的调试器&#xff0c;进行测试&#xff0c;仅此进行记录。 开发板HPM6750EVK2 openocd调试器图片 openocd调试器&#xff0c;淘宝链接 http://e.tb.cn/h.TZH7b…

斐波那契数的第n个数代码分享(c基础)

1&#xff1a;迭代 //斐波那契数的第n个数 #include<stdio.h> //unsigned long long Fib(n) //{ // // if (1 n || 2 n) // return 1; // else return Fib((n - 1) Fib((n - 2); // // //} unsigned long long Fib(n) {if (n 1 || n 2)return 1;else{int j 3;u…

测试实项中的偶必现难测bug--一键登录失败

问题描述:安卓和ios有出现部分一键登录失败的场景,由于场景比较极端,衍生了很多不好评估的情况。 产生原因分析: 目前有解决过多次这种行为的问题,每次的产生原因都有所不同,这边根据我个人测试和收集复现的情况列举一些我碰到的: 1、由于我们调用的是友盟的一键登录的…

私域流量圈层在新消费时代的机遇与挑战:兼论开源 AI 智能名片、2 + 1 链动模式、S2B2C 商城小程序的应用

摘要&#xff1a;本文剖析了私域流量圈层在新消费时代呈现出的独特温度与信任优势&#xff0c;阐述了从传统销售到新消费转型中用户心理的变化。同时&#xff0c;强调了内容对于私域流量的关键作用&#xff0c;并分析开源 AI 智能名片、2 1 链动模式、S2B2C 商城小程序在私域流…

WPF之iconfont(字体图标)使用

1&#xff0c;前文&#xff1a; WPF的Xaml是与前端的Html有着高度相似性的标记语言&#xff0c;所以Xaml也可同Html一般轻松使用阿里提供的海量字体图标&#xff0c;从而有效的减少开发工作度。 2&#xff0c;下载字体图标&#xff1a; 登录阿里图标库网iconfont-阿里巴巴矢量…

[Meachines] [Medium] MonitorsThree SQLI+Cacti-CMS-RCE+Duplicati权限提升

信息收集 IP AddressOpening Ports10.10.11.30TCP:22&#xff0c;80 $ nmap -p- 10.10.11.30 --min-rate 1000 -sC -sV -Pn PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0) | …

AndroidStudio-文本显示

一、设置文本的内容 1.方式&#xff1a; &#xff08;1&#xff09;在XML文件中通过属性&#xff1a;android:text设置文本 例如&#xff1a; <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.andr…

pyspark入门基础详细讲解

1.前言介绍 学习目标&#xff1a;了解什么是Speak、PySpark&#xff0c;了解为什么学习PySpark&#xff0c;了解课程是如何和大数据开发方向进行衔接 使用pyspark库所写出来的代码&#xff0c;既可以在电脑上简单运行&#xff0c;进行数据分析处理&#xff0c;又可以把代码无缝…

uniapp上拉刷新下拉加载

方法一&#xff1a; z-paging 的组件库&#xff1a; show-loading-more-no-more-view"false" 该属性控制是否显示 "加载更多" 或 "没有更多" 的提示。如果设为 false&#xff0c;则不会显示这些提示。如果设为 true&#xff0c;当数据加载完毕…

CSS教程(二)- CSS选择器

1. 作用 匹配文档中的某些元素为其应用样式。根据不同需求把不同的标签选出来。 2. 分类 分类 基础选择器 包含 标签选择器、ID选择器、类选择器、通用选择器等 复合选择器 包含 后代选择器、子代选择器、伪类选择器等 1 标签选择器 介绍 又称为元素选择器&#xff0c;根…

LeetCode 56.合并区间

思路&#xff1a; 类似于用最少的箭射气球题目&#xff0c;最主要是要处理区间之间是否有重叠&#xff0c;如果无重叠则加入数组&#xff0c;如果有重叠&#xff0c;则需要重新设判断的边界&#xff0c;与下一个区间继续判断。 难点在于 代码用法 需熟练掌握 思想简单&#…

【MySQL】MySQL基础知识复习(上)

前言 本篇博客将复习MySQL的基础知识&#xff0c;及着重复习CRUD&#xff08;增删查改&#xff09;操作。 目录 一.MySQL数据库基础知识 1.数据库操作 1.1显示当前的数据库 1.2 创建数据库 1.3 使用数据库 1.4 删除数据库 2.数据类型 2.1.数字类型 2.2字符串类型 2.3…

华为大变革?仓颉编程语言会代替ArkTS吗?

在华为鸿蒙生态系统中&#xff0c;编程语言的选择一直是开发者关注的焦点。近期&#xff0c;华为推出了自研的通用编程语言——仓颉编程语言&#xff0c;这引发了关于仓颉是否会取代ArkTS的讨论。本文将从多个角度分析这两种语言的特点、应用场景及未来趋势&#xff0c;探讨仓颉…

稀硫酸介质中 V 型球阀的材质选择与选型要点-耀圣

稀硫酸介质中 V 型球阀的材质选择与选型要点 在工业生产中&#xff0c;稀硫酸是一种常见的化学介质&#xff0c;对于输送和控制稀硫酸的阀门&#xff0c;正确的材质选择和选型至关重要。本文将介绍稀硫酸介质中 V 型球阀的材质选择&#xff0c;并提供一些选型的要点。 一、稀硫…