力扣刷题:19. 删除链表的倒数第 N 个结点(翻转链表模板题!!!)

这篇博客介绍了四种不同的方法来删除链表中的倒数第n个节点,包括使用vector、两遍遍历、栈和快慢指针。每种方法都有详细的步骤解释和代码实现,展示了链表操作的多种思路。同时,文章强调了一题多解的重要性,特别是在面试中的应用价值。
摘要由CSDN通过智能技术生成

题目要求

在这里插入图片描述

版本一:使用vector容器装结点指针

(不知道这种方法在面试的时候能不能用…)

整体思路

创建一个存放结点指针的容器,遍历并将整个链表存储进容器之中。

根据n算出需要删除的节点位置indexDelete

删除时需要分情况讨论:
如果indexDelete=0,为删除头结点或者只存在一个节点。只需令head = head->next即可。
如果indexDelete=尾节点,为删除尾节点。只需令倒数第二个节点的next指向nullprt即可。
其它情况为删除中间节点。只需令indexDeletre-1节点的next指针指向indexDelete节点的next指针指向的结点即可。

代码

class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) 
{
  vector<ListNode*> v;
  ListNode* p = head;
  while (p != nullptr)
  {
    v.push_back(p);
    p = p->next;
  }
  unsigned indexDelete = v.size() - n;
  //只有一个元素 或者 删除头元素
  if (indexDelete == 0)
  {
    head = v[0]->next;
    /*一般来说是要delete的,但因为这些内存不是new出来的,按本题的情景就不delete了
    v[0] = nullptr;
    delete v[0];
    */
  }
  //删除尾元素:不可能只有一个元素
  else if (indexDelete == v.size() - 1)
  {
    v[v.size() - 2]->next = nullptr;
    /*
    v[v.size() - 1]->next = nullptr;
    delete v[v.size() - 1];
    */
  }
  //删除中间元素
  else
  {
    v[indexDelete - 1]->next = v[indexDelete]->next;
    v[indexDelete]->next = nullptr;
  }
  return head;
}
};

学到了什么

1、将容器存入容器里,实现原容器不能实现的操作。这里是将列表存入vector里,实现了列表无法随机访问的操作,这好像是c++primier里面介绍的方法,具体在第几章忘了…

版本二:两遍遍历

整体思路

第一遍遍历记录链表的结点数量,第二遍遍历根据index
删除指定结点。
需要注意的是,有可能遇到链表中只有一个结点,且删除该结点的情况。此时head就会变成nullptr。所以需要在头结点之前添加一个临时结点。

代码

class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
    //临时头结点
    ListNode *temp = new ListNode();
    temp->next = head;
    ListNode* p = head;
    //第一遍遍历记录数量
    int count = 0;
    while (p!= nullptr)
    {
        p = p->next;
        ++count;
    }
    //第二遍遍历删除指定结点
    p = temp;
    int index = 0;
    while (true)
    {
        if (count - index == n)
        {
            p->next = p->next->next;
            break;
        }
        ++index;
        p = p->next;
    }
    return temp->next;
}
};

版本三:栈

整体思路

遍历一遍链表,将所有结点存入栈中。根据栈的特点,链表最后的结点将会位于栈的顶端。这样就可以通过pop操作从尾部往回,接触到倒数第n个结点。

代码

class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
    ListNode* temp = new ListNode();
    temp->next = head;
    std::stack<ListNode*> s;
    ListNode* p = temp;
    while (p != nullptr)
    {
        s.push(p);
        p = p->next;
    }
    int count = 0;
    while (true)
    {
        if (count == n)
        {
            auto node = s.top();
            node->next = node->next->next;
            break;
        }
        s.pop();
        ++count;
    }
    return temp->next;
}
};

版本四:快慢指针

整体思路

创建一个快指针first,一个慢指针second。让快指针维持在慢指针前面第n个结点处。这样当快指针指向最后一个结点时,慢指针自然就指向了倒数第n个结点

代码

class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
    ListNode* temp = new ListNode();
    temp->next = head;
    ListNode* first = head, *second = temp;
    int count = 1;
    while (count != n)
    {
        first = first->next;
        ++count;
    }
    while (first->next != nullptr)
    {
        first = first->next;
        second = second->next;
    }
    second->next = second->next->next;
    return temp->next;
}
};

学到了什么

一题多解,掌握了与链表倒序相关的模板操作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值