原题链接: 19. 删除链表的倒数第 N 个结点 - 力扣(Leetcode)
tag: 双指针, 链表.
一. 题目
给你一个链表, 删除链表的倒数第 n 个结点, 并且返回链表的头结点.
二. 题解
本题需要删除链表的倒数第 N 个节点.
先使用双指针的方法, 找到倒数第 N + 1 个节点(即倒数第 N 个节点的前驱节点).
再对链表中的第 N 个节点进行删除操作, 由于会涉及头删的情况, 所以我们设置一个虚拟头节点(dummy).
删除前.
设置一个虚拟头节点.
ListNode* dummy = new ListNode(0, head);
定义 slow 指针指向虚拟头节点, 定义 fast 指针指向头节点.
ListNode* slow = dummy, * fast = head;
由于 slow 指针和 fast 指针需要间隔 n + 1 步, 所以 fast 指针先走 n 步.
fast = fast->next;
fast = fast->next;
当 n == 0 时, 第一个 while 循环终止.
此时 fast 指针和 slow 指针间隔 n + 1 步, 在这之后我们同时使用 slow 和 fast 对链表进行遍历.
slow = slow->next;
fast = fast->next;
重复这一步骤.
重复这一步骤.
当 fast == nullptr 时, 第二个 while 循环终止.
当 fast 指针遍历到链表末尾时(指向空), slow 指针恰好指向倒数第 N + 1 个节点, 即要删除的倒数第 N 个节点的前驱节点, 此时我们便可以对第 N 个节点进行删除操作了.
ListNode* temp = slow->next;
slow->next = temp->next;
delete temp;
删除链表的倒数第 N 个节点后返回链表的头节点.
head = dummy->next;
delete dummy;
删除后.
三. 复杂度分析
时间复杂度: O(N), 其中 N 是链表的长度.
空间复杂度: O(1).
四. 代码
/**
* 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* slow = dummy, * fast = head; // 定义慢指针 slow, 快指针 fast
while (n--) { // 快指针先走 n 步
fast = fast->next;
}
while (fast != nullptr) { // 快慢指针同时遍历链表
slow = slow->next;
fast = fast->next;
}
ListNode* temp = slow->next; // 对链表中的第 N 个节点进行删除操作
slow->next = temp->next;
delete temp;
head = dummy->next; // 返回新的头节点
delete dummy;
return head;
}
};