一、题目介绍
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
二、解题思路
由于我们需要找到倒数第 n 个节点,因此我们可以使用两个指针 fast 和 slow同时对链表进行遍历,并且 fast 比 slow 超前 nn 个节点。当 fast 遍历到链表的末尾时,slow就恰好处于倒数第 n 个节点。
具体地,初始时 fast和 slow均指向头节点。我们首先使用 fast 对链表进行遍历,遍历的次数为 n。此时,fast 和 slow 之间间隔了 n-1个节点,即 fast 比 slow超前了 n个节点。
在这之后,我们同时使用fast 和 slow对链表进行遍历。当fast遍历到链表的末尾(即 fast为空指针)时,slow 恰好指向倒数第 nn个节点。
如果我们能够得到的是倒数第 n 个节点的前驱节点而不是倒数第 n 个节点的话,删除操作会更加方便。因此我们可以考虑在初始时将slow 指向哑节点,其余的操作步骤不变。这样一来,当 fast遍历到链表的末尾时,slow的下一个节点就是我们需要删除的节点。
三、代码
/**
* 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) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummy = new ListNode(0, head);
ListNode* fast=head;
ListNode* slow = dummy;
while(n>0){
fast=fast->next;
n--;
}
for (int i = 0; i < n; ++i) {
fast=fast->next;
}
while(fast){
fast=fast->next;
slow=slow->next;
}
slow->next=slow->next->next;
ListNode* ans = dummy->next;
delete dummy;
return ans;
}
};
四、复杂度分析
时间复杂度:O(L),其中 L是链表的长度。
空间复杂度:O(1)。
欢迎关注微信公众号【算法攻城师】