首页 > 其他分享 > LC19. 删除链表的倒数第 N 个结点

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

时间:2023-05-16 16:12:36浏览次数:42  
标签:结点 slow 删除 fast next 链表 LC19 倒数第

删除链表的倒数第N个结点(中等)

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

 

示例:

示例一:
输入:head = [1,2,3,4,5], n = 2 输出:[1,2,3,5]
示例二:
输入:head = [1], n = 1 输出:[]
实例三:
输入:head = [1,2], n = 1 输出:[1]

A:思路:对于本题来讲,其本质仍为删除链表中的某个结点,而想要删除链表中的结点,则一般需要找到待删除结点的上一个结点,然后改变next指针即可。

    该题的需求是删除倒数第n个结点,那么我们的任务就分为了两步,第一步是找到待删除结点的上一个结点(为了方便删除),第二是更改next指针指向即可。很显然,该题的难点在于:如何去找到倒数第n个结点的上一个结点呢。归根结底,我们其实需要找的是倒数第 n + 1 个结点(第一步),而删除的是倒数第 n 个结点(第二步)。

    对于链表这一类的题来讲,我们最好都去创建一个虚拟哑结点去指向头结点,这么做的目的就是:插入或删除链表中的任何结点都是很方便的。我们知道,在链表中头和尾是比较特殊的,一个没有前驱,一个没有后继,尤其是操作头结点时,若有了虚拟哑结点那就相当方便和简洁了。接下来开始解题,分两步走:

    第一步:找到第 n + 1 个结点(利用快慢双指针)

    定义两个快慢指针slow和fast,起始均指向dummyNode,随后为了使得后续同时移动快慢指针时,使得二者之间的距离恒为 n + 1 ,故先让fast移动 n + 1次。

    即:

while(n != 0 && fast != null){ // while循环中移动了n次
            fast = fast.next;
            --n;
     }
     fast = fast.next; // 这里再移动一次,fast一共移动了n + 1次

     此时,fast指向了正数第 n + 2个结点,但是我们要找的是倒数第 n + 1个结点。现在哑结点和fast指针所指结点之间是一共有 n 个结点的,随后,当fast != null时,同时移动fast和slow,当fast指向null时,slow正好指向了倒数第 n + 1个结点。

     即:

while(fast != null){ //  当fast不为空时,同时移动slow和fast
            fast = fast.next; //  fast最终指向了null
            slow = slow.next; //  slow最终指向了待删除节点的上一个结点,即倒数 n + 1 个结点
        }

     第二步:删除的是倒数第 n 个结点

    当找到倒数第 n + 1个结点后,删除就非常简单了,利用 slow.next = slow.next.next 即可。

    这里也要注意一点的就是,删除结点对于不用的编程语言来讲,并非是slow.next = slow.next.next 就万事大吉了。这只是在逻辑上的删除,而在物理即内存中并不一定就被删除掉了。对于Java语言来说,我们并不需要做多余的操作,垃圾回收器gc会帮我们去回收该结点并释放内存;但对于C++来讲,就需要手动的去删除和释放内存空间了,毕竟偏底层的高级语言可以较为直接的去操作内存,即是优点但也可能是个缺点,所以对于C++来说,逻辑上删除后,还需要物理上的手动删除,即最后的删除操作应为① ListNode temp = slow.next; ②slow.next = slow.next.next; ③ delete(temp);

    以下是Java代码,仅供参考:

/**
 *  这里是链表结构的定义,面试中也有可能考察,需要会写出。
* Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode() {} * ListNode(int val) { this.val = val; } * ListNode(int val, ListNode next) { this.val = val; this.next = next; } * } */ class Solution { public ListNode removeNthFromEnd(ListNode head, int n) { ListNode dummyNode = new ListNode(0, head); // 1. 定义一个哑结点,并初始指向头结点 ListNode fast = dummyNode, slow = dummyNode; // 2. 分别定义一个快指针fast和慢指针slow均初始指向哑结点 while(n != 0 && fast != null){ // 3. 在保证fast不为空指针的情况下将其向前挪动 n 次 fast = fast.next; --n; } fast = fast.next; // 4. fast往后多移动一位,为了使得后面slow和fast一起移动时,slow最终可以指向待删除节点的上一个节点,也是为了删除方便 while(fast != null){ // 5. 当fast不为空时,同时移动slow和fast fast = fast.next; // 6. fast最终指向了null slow = slow.next; // 7. slow最终指向了待删除节点的上一个结点,即倒数 n + 1 个结点处 } slow.next = slow.next.next; // 8. 更改slow的next指针,以删除倒数第 n 个结点 return dummyNode.next; // 9. 返回哑结点的下一个结点,即head结点 } }

标签:结点,slow,删除,fast,next,链表,LC19,倒数第
From: https://www.cnblogs.com/fxy0715/p/17405712.html

相关文章

  • (双指针)剑指 Offer 22. 链表中倒数第k个节点
    题目描述:输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。例如,一个链表有6个节点,从头节点开始,它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个节点是值为4的节点。    classSolution......
  • 图解LeetCode——234. 回文链表
    一、题目给你一个单链表的头节点head,请你判断该链表是否为回文链表。如果是,返回true;否则,返回false。二、示例2.1>示例1:【输入】head=[1,2,2,1]【输出】true2.2>示例2:【输入】head=[1,2]【输出】false提示:链表中节点数目在范围[1,10^5]内0<=Node.v......
  • 链表排序
    /***Definitionforsingly-linkedlist.*structListNode{*intval;*ListNode*next;*ListNode():val(0),next(nullptr){}*ListNode(intx):val(x),next(nullptr){}*ListNode(intx,ListNode*next):val(x),next(next){}*......
  • Redis数据结构二之SDS和双向链表
    本文首发于公众号:Hunter后端原文链接:Redis数据结构二之SDS和双向链表这一篇笔记介绍一下SDS(simpledynamicstring)和双向链表。以下是本篇笔记目录:SDS常数复杂度获取字符串长度杜绝缓冲区溢出减少修改字符串带来的内存重分配次数二进制安全兼容C字符串函数双向链......
  • 剑指 Offer 18. 删除链表的节点
    题目描述:给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。返回删除后的链表的头节点。     复杂度分析:  时间复杂度O(N):N为链表长度,删除操作平均需循环N/2次,最差N次。  空间复杂度O(1):cur,pre占用常数大小额外空间。class......
  • 5-14打卡 力扣24. 两两交换链表中的节点
    给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。示例1:输入:head=[1,2,3,4]输出:[2,1,4,3]示例2:输入:head=[]输出:[]示例3:输入:head=[1]输出:[1]来源:力扣(LeetCode)链接:https://leetco......
  • 链表的倒数第k个节点
     /***Definitionforsingly-linkedlist.*structListNode{*intval;*ListNode*next;*ListNode(intx):val(x),next(NULL){}*};*///classSolution{//public://ListNode*getKthFromEnd(ListNode*head,intk){//if(head!=......
  • 【❂Java集合】循环链表和双向链表的区别是是什么
    最后一个结点指针指向不同在建立一个循环链表时,必须使其最后一个结点的指针指向表头结点,而不是像双向链表那样置为NULL。此种情况还用于在最后一个结点后插入一个新的结点。判断链域值不同在判断是否到表尾时,是判断该结点链域的值是否是表头结点,当链域值等于表头指针时,说明已到......
  • 链表算法 篇二
    合并K个有序列表packagecom.algorithm202305.linkedlist;importjava.util.List;importjava.util.PriorityQueue;/***合并K个有序链表*合并K个有序链表的逻辑类似于合并两个有序链表,难点在于,如何快速得到K个节点中最小的节点,接到结果链表上*这里我们就要用到优先级......
  • 力扣题目两两交换链表中的节点
    题目:给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)示例1:解题思路对于这道题我们可以为原链表增加一个哨兵卫,然后创建三个指针,最前面的指针用于判断是否还存在需要交换的节点,后面的两个节点用于交换......