leetcode原题链接:删除链表的倒数第 N 个结点
题目描述
删除链表的倒数第 N 个结点。
给你一个链表,删除链表的倒数第 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
解题方法:双指针法。如下三点需要注意:
1. 快指针跟慢指针的距离应该始终保持距离为n+1,也就是快指针在慢指针第n+1个节点后(从慢指针下一个节点开始数),这样当快指针到达最后nullptr的时候,慢指针在倒数第n+1个节点的位置(因为要删除第n个节点,我们需要知道第n个节点前一个节点是什么)。
2. 快慢指针的开始位置。快指针指向head节点,慢指针的开始位置在快指针的前面,这样初始位置快慢指针距离为1,快指针只需要向前先走n步即可保持跟慢节点n+1的距离。如果快慢指针初始位置相同,则快节点需要先走n+1步。
3. 使用哑节点可以减少删除的节点为head节点的情况。例如链表的长度为n的时候,删除倒数第N个节点,正常需要删除head节点的情况,但是如果引入了dummy_node,就不需要考虑这类问题。
C++代码
#include <iostream>
#include <memory> // std::shared_ptr
/**
* 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) {}
* };
1—>2->3->4->5->6
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
if (!head) {
return nullptr;
}
//引入哨兵节点: 可以不用单独考虑是否删除的是原链表的头节点
std::shared_ptr<ListNode> dummy_node(new ListNode(0));
dummy_node->next = head;
ListNode *pre = dummy_node.get();//pre指向虚拟节点位置
ListNode *p = head;//注意开始位置p在pre的后面一个节点,这样就不用p走n+1步,解决n正好等于链表长度的问题
// 前驱节点先走n步骤
for (int i = 0; i < n; i++) {
if (!p) {
return nullptr;
}
p = p->next;
}
// 两指针同时遍历,当前驱指针p走到nullptr时,pre指向倒数第n个节点的前一个节点
while (pre && p) {
pre = pre->next;
p = p->next;
}
// 删除倒数第n个结点
pre->next = pre->next->next;
return dummy_node->next;
}
};