原题链接: 2095. 删除链表的中间节点 - 力扣(Leetcode)
tag: 双指针, 链表.
在阅读本文前, 请先阅读如下两篇题解.
Leetcode 876. 链表的中间结点 - 掘金 (juejin.cn)
Leetcode 19. 删除链表的倒数第 N 个结点 - 掘金 (juejin.cn)
一. 题目
给你一个链表的头节点 head . 删除 链表的 中间节点 , 并返回修改后的链表的头节点 head .
长度为 n 链表的中间节点是从头数起第 ⌊n / 2⌋ 个节点(下标从 0 开始), 其中 ⌊x⌋ 表示小于或等于 x 的最大整数.
- 对于
n=1、2、3、4和5的情况, 中间节点的下标分别是0、1、1、2和2.
二. 题解
本题需要删除链表的中间节点, 则我们需要找到链表中间节点的前驱节点.
使用 快慢指针法 找到链表的中间节点.
定义 prev 指针保存 slow 指向节点的前一个节点从而定位中间节点的前驱节点.
定义一个虚拟头节点 dummy , 定义 prev 指针用来标记被删除节点的前驱节点.
ListNode* dummy = new ListNode(0, head), * prev = dummy;
定义慢指针 slow, 快指针 fast.
ListNode* slow = head, * fast = head;
fast != nullptr && fast->next != nullptr;
用 prev 指针维护 slow 节点的前驱节点.
prev = slow;
慢指针走一步.
slow = slow->next;
快指针走两步.
fast = fast->next->next;
重复这一步骤直至 fast == nullptr 或 fast->next == nullptr .
删除链表的中间节点.
prev->next = slow->next;
delete slow;
返回新链表的头节点.
head = dummy->next;
delete dummy;
return head;
三. 复杂度分析
时间复杂度: 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* deleteMiddle(ListNode* head) {
ListNode* dummy = new ListNode(0, head), * prev = dummy; // 定义一个虚拟头节点 dummy , 定义 prev 指针用来标记被删除节点的前驱节点
ListNode* slow = head, * fast = head; // 定义慢指针 slow, 快指针 fast
while (fast && fast->next) {
prev = slow; // 用 prev 指针维护 slow 节点的前驱节点
slow = slow->next; // 慢指针走一步
fast = fast->next->next; // 快指针走两步
}
prev->next = slow->next; // 删除链表的中间节点
delete slow;
head = dummy->next; // 返回新链表的头节点
delete dummy;
return head;
}
};