踩坑记录[6]——LeetCode 19题:删除链表的倒数第 N 个结点

踩坑记录[6]——LeetCode 19题:删除链表的倒数第 N 个结点

题目描述

题目链接

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

示例 1:

踩坑记录[6]——LeetCode 19题:删除链表的倒数第 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

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

答案(C++语言,已通过LeetCode测试)

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
      ListNode *p = new ListNode(-1);
      p->next = head;
      ListNode *fast = p, *slow = p;
      for(int i=0;i<n+1;i++)
        fast = fast->next;
      
      while(fast != nullptr){
        slow = slow->next;
        fast = fast->next;
      }

      slow->next = slow->next->next;

      return p->next;
    }
};

方案描述

在这个问题中,我们需要删除链表中的倒数第n个节点。为了找到倒数第n个节点的前一个节点(也就是倒数第n+1个节点),我们使用了双指针的方法。

首先,我们创建了一个虚拟头节点 p,将其指向原始链表的头节点 head。这样做的目的是为了处理特殊情况,例如链表长度为1或者删除的是头节点的情况。接下来,我们使用两个指针 fastslow,都初始化为虚拟头节点 p

然后,我们让 fast 指针先向前移动n+1步,使其指向第n+1个节点。为什么要向前移动n+1步而不是n步呢?因为我们要找的是倒数第n个节点的前一个节点,所以 fast 指针需要多向前移动一步。在 fast 指针移动的过程中,我们需要确保 fast 指针不会越界,因此需要对链表长度不足n+1的情况进行处理,这也是为什么我们使用了虚拟头节点。

接下来,我们让 fast 指针和 slow 指针同时向前移动,直到 fast 指针指向链表的最后一个节点为止。这样,slow 指针就指向了倒数第n+1个节点。

然后,我们将倒数第n+1个节点的 next 指针指向其下一个节点的下一个节点,从而删除了倒数第n个节点。

最后,我们返回虚拟头节点 p 的下一个节点,即为删除倒数第n个节点后的链表头节点。

踩坑记录

题目难度:中等

本题目为寻找链表中倒数第n个结点的典型例题,核心解题思想:定义两个指针快慢指针,先让快指针走n步,剩下m-n步,两个指针一起走,就能到第m-n个结点(也就是倒数第n个结点)!

  • 要寻找倒数第n+1个结点而不是倒数第n个

    由于本题的目的是删除倒数第n个结点,因此需要找到这个结点的前一个结点,也就是倒数第n+1个结点。因此,在fast指针前进时,前进了n+1步,

    for(int i=0;i<n+1;i++)  // n+1
              fast = fast->next;
    
  • 使用虚拟头节点避免空指针报错

    若链表长度为1或者删除的是头节点,可能会导致指针取fast->next报错。于是,刚开始时,建立虚拟头节点,该结点的下一个结点为实际的头节点。

    ListNode *p = new ListNode(-1);
    p->next = head;
    

    注意:由于使用了虚拟头节点,所以最终应该返回return p->next;

思路参考

双指针技巧秒杀七道链表题目 | labuladong 的算法笔记

你可能感兴趣的:(leetcode,链表,算法,c++)