题目
解答1:找位置
思路
先找位置再删除,最简单的方法。
需要的头文件
无
代码
/*
* @lc app=leetcode.cn id=19 lang=cpp
*
* [19] 删除链表的倒数第 N 个结点
*/
// @lc code=start
/**
* 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) {}
* };
*/
using namespace std;
class Solution
{
public:
int getLength(ListNode *head)
{
int length = 0;
while (head)
{
length++;
head = head->next;
}
return length;
}
ListNode *removeNthFromEnd(ListNode *head, int n)
{
//新建一个头指针保存头结点
ListNode *headpointer = new ListNode();
headpointer->next = head;
/*也可以ListNode *headpointer = new ListNode(0,head);*/
int Listlen = getLength(head);
//头指针副本
ListNode *hp = headpointer;
for (int i = 1; i < Listlen - n + 1; i++)
{
hp = hp->next;
}
//常规操作
hp->next = hp->next->next;
//new用完请释放,记得新建一个结点保存一下头结点
ListNode *resnode = headpointer->next;
delete headpointer;
//返回头指针,注意这里不能直接headpointer->next,new了一定要delete
return resnode;
}
};
// @lc code=end
时间复杂度和空间复杂度
-
时间复杂度: O(N) ,N为链表长度。
-
空间复杂度:O(1) 。
解答2:栈方法
思路
一次性放入所有的元素,再退出N个元素,而栈特性就是只对当前top元素进行操作,恰好满足题目要求。
需要的头文件
stack
代码
/*
* @lc app=leetcode.cn id=19 lang=cpp
*
* [19] 删除链表的倒数第 N 个结点
*/
// @lc code=start
/**
* 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) {}
* };
*/
#include <stack>
using namespace std;
class Solution
{
public:
ListNode *removeNthFromEnd(ListNode *head, int n)
{
//新建一个头指针保存头结点
ListNode *headpointer = new ListNode();
headpointer->next = head;
//栈STL
stack<ListNode *> stk;
//放入所有的元素,再依次退出N个元素
ListNode *cur = headpointer;
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;
//new用完释放,记得新建一个结点保存一下头结点
ListNode *resnode = headpointer->next;
delete headpointer;
//返回头指针,注意这里不能直接headpointer->next,new了一定要delete
return resnode;
}
};
// @lc code=end
时间复杂度和空间复杂度
-
时间复杂度: O(N) ,N为链表长度。
-
空间复杂度:O(N) ,因为开辟了一个长度为N的栈空间。
解答3:快慢指针
思路
链表+倒数N=快慢指针解决。
从零开始数,快指针指向头结点,慢指针指向新建的头指针。当快指针指到N的时候,慢指针和快指针一起动。当快指针指向NULL时,慢指针刚好就是指向倒数第N个数据。(简单的代数学)
需要的头文件
无
代码
/*
* @lc app=leetcode.cn id=19 lang=cpp
*
* [19] 删除链表的倒数第 N 个结点
*/
// @lc code=start
/**
* 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) {}
* };
*/
using namespace std;
class Solution
{
public:
ListNode *removeNthFromEnd(ListNode *head, int n)
{
//新建一个头指针保存头结点
ListNode *headpointer = new ListNode();
headpointer->next = head;
//快慢指针
ListNode *fastptr = head;
ListNode *slowptr = headpointer;
//快指针先移到 N 的位置,此时快慢指针相隔就是N个结点(如慢0快3,中间隔了1和2两个结点)
for (int i = 0; i < n; i++)
{
fastptr = fastptr->next;
}
//慢指针和快指针一起动,到快指针指向nullptr时退出
while (fastptr)
{
fastptr = fastptr->next;
slowptr = slowptr->next;
}
//此时慢指针就在倒数第N个位置,删除即可
slowptr->next = slowptr->next->next;
//new用完释放,记得新建一个结点保存一下头结点
ListNode *resnode = headpointer->next;
delete headpointer;
//返回头指针,注意这里不能直接headpointer->next,new了一定要delete
return resnode;
}
};
// @lc code=end
时间复杂度和空间复杂度
-
时间复杂度: O(N) ,N为链表长度。
-
空间复杂度:O(1) 。
反思与总结
从多个角度观察问题,比如想到栈特性、快慢指针可以解决这一类“链表倒数问题”。