题目要求
版本一:使用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;
}
};
学到了什么
一题多解,掌握了与链表倒序相关的模板操作