Leetcode19 删除链表的倒数第N个节点

Leetcode 19.

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

https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/

最近在刷Leetcode,这道题给的题解让人耳目一新。

1.方法一

  • 首先求长度,自己写一个函数,删除倒数第N个节点,就是删除正数第L-N+1个节点,L为长度,注意链表长度从1开始计数。这个不难想到,题解的亮点在于引入了哑节点,什么是哑节点,为什么要引入哑节点?
  • https://blog.csdn.net/x55x5/article/details/82493185?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control
  • https://blog.csdn.net/weixin_44388094/article/details/100929840
  • 这两篇文章大佬讲得很透彻,尤其是第一篇大佬讲的,强推。总的来说哑节点它的 next 指针指向链表的头节点。这样一来,我们就不需要对头节点进行特殊的判断了,它的初始值就为NULL,但是它在堆中占有一定的空间,可以避免边界问题的处理,简化代码,例如在本题中,如果我们要删除节点 yy,我们需要知道节点 yy 的前驱节点 xx,并将 xx 的指针指向 yy 的后继节点。但由于头节点不存在前驱节点,因此我们需要在删除头节点时进行特殊判断。但如果我们添加了哑节点,那么头节点的前驱节点就是哑节点本身,此时我们就只需要考虑通用的情况即可。
/**
 * 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:
    int getLength(ListNode* head)
    {
        int length=0;
        while(head)
        {
            head=head->next;
            ++length;
        }
        return length;
    }
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummy=new ListNode(0,head);//哑节点
        int length=getLength(head);
        ListNode* cur=dummy;//要进行遍历所用的节点
        for(int i=1;i<length-n+1;i++)
        {
            cur=cur->next;
        }
        cur->next=cur->next->next;
        ListNode* ans=dummy->next;
        delete dummy;//释放空间
        return ans;

    }
};

2.方法二

快慢指针法:删除链表的倒数第 n 个结点,首先要确定倒数第 n 个节点的位置。

我们可以设定两个指针,分别为 slow 和 fast,刚开始都指向 head。

然后先让 fast 往前走 n 步,slow 指针不动,这时候两个指针的距离为 n。

再让 slow 和 fast 同时往前走(保持两者距离不变),直到 fast 指针到达结尾的位置。

这时候 slow 会停在待删除节点的前一个位置,让 slow->next = slow->next->next 即可。

但这里有一个需要注意的边界情况是:如果链表的长度是 L,而我们恰好要删除的是倒数第 L 个节点(删除头节点),这时候 fast 往前走 n 步之后会变为 null,此时我们只需要让 head = slow->next 即可删除。


```cpp
在这里插入代码片/**
 * 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->next==nullptr)//样例二的测试
        return NULL;
     ListNode* fast=head;
     ListNode* slow=head;
     for(int i=1;i<=n;i++)
     {
        fast=fast->next;//注意是<=n而非<n可以自己纸上模拟一下
     } 
     if(fast==nullptr)//边界情况 删除倒数第L个节点即为删除头节点 L代表链表长度
     {
         head=slow->next;//直接让head=slow->next即可
     }
     else
     {
         while(fast->next!=nullptr)
         {
             slow=slow->next;
             fast=fast->next;
         }
         slow->next=slow->next->next;
     }
     return head;
    }
};

在这里插入图片描述

3.方法三

方法三其实是用栈的方法实现,栈先进后出。弹出栈的第 n 个节点就是需要删除的节点,并且目前栈顶的节点就是待删除节点的前驱节点。如此,删除操作就变得十分方便。

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummy = new ListNode(0, head);
        stack<ListNode*> stk;
        ListNode* cur = dummy;
        while (cur) {
            stk.push(cur);
            cur = cur->next;
        }
        for (int i = 0; i < n; ++i) {
            stk.pop();
        }
        ListNode* prev = stk.top();
        prev->next = prev->next->next;
        ListNode* ans = dummy->next;
        delete dummy;
        return ans;
    }
};//具体参考的官方题解。

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下 4载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下载 4使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下载 4使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值