主要思路
建立哑结点
双指针法:first指针先走n步后,first和second一起走,当first指向null时,second正好指向要删除的结点,因为本题要删除该节点,返回删除后的链表,所以我们让second指向哑结点,最后second正好指向待删除结点的前一个结点,修改指针指向即,最后记得释放哑结点
栈:同样设置哑结点指向head,然后依次入栈,最后将倒数n个元素出栈,那么此时的栈顶元素即为待删除结点的前一个结点,修改指针指向就好了。
本题的关键还是找到待删除结点的前一个结点。当然除了以上两种方法还有比较好想到的:遍历链表统计总个数cnt,待删除结点即为cnt-n,待删除结点的前一个结点即为cnt-n-1(下标从0开始)
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){}
};
//19. 删除链表的倒数第 N 个结点
//双指针法找到待删除的结点的前一个结点 与前面的题不同的是这里sec指向哑结点
//最终sec就指向待删除结点的前一个结点,好处理
class Solution {
public:
ListNode *removeNthFromEnd(ListNode *head,int n) {
if(head==nullptr)return head;
ListNode *ret = new ListNode(0,head);
ListNode *fir = head;
ListNode *sec = ret;
while(n--) {
fir = fir->next;
}
while(fir) {
fir = fir->next;
sec = sec->next;
}
sec->next = sec->next->next;
ListNode *ans = ret->next;
delete ret;
return ans;
}
};
//用栈 弹出倒数n个后,栈顶元素即为待删除结点的前一个元素
class Solution {
public:
ListNode *removeNthFromEnd(ListNode *head,int n) {
if(head==nullptr)return head;
ListNode *fake = new ListNode(0,head);
stack<ListNode *> sta;
ListNode *cur = fake;
while(cur) {
sta.push(cur);
cur = cur->next;
}
while(n--) {
sta.pop();
}
ListNode *prev = sta.top();//取出栈顶元素,改变指向
prev->next = prev->next->next;
ListNode *ret = fake->next;
delete fake;
return ret;
}
};