19.删除链表的倒数第 N 个结点
题解:删除链表的倒数第 N 个节点(LeetCode 第 19 题)
一、题目描述
给定一个单链表,删除链表的倒数第 n
个节点,并返回链表的头节点。
二、解题思路
如果我们从头遍历链表,想找“倒数第 n 个节点”,必须知道整个链表长度。但那样就要 遍历两次链表。
为了优化效率,这里我们使用一个非常常用的技巧:
双指针法(快慢指针) —— 只遍历一次!
技巧关键:
- 创建两个指针
p1
、p2
; - 先让
p1
先走 n 步; - 然后
p1
和p2
一起走,直到p1
到达链表末尾; - 此时
p2
就正好在 倒数第 n 个节点的前一个节点!
这样我们就可以通过 p2->next = p2->next->next
删除目标节点了。
为了简化边界处理(比如删除的是头结点),我们使用一个 虚拟头结点 dummy。
三、代码实现
/*** 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:// 主函数:删除倒数第 n 个节点ListNode* removeNthFromEnd(ListNode* head, int n) {// 虚拟头节点,处理头节点被删除的情况ListNode* dummy = new ListNode(0);dummy->next = head;// 找到倒数第 n+1 个节点(即待删节点的前一个)ListNode* x = findFromEnd(dummy, n + 1);// 删除操作:跳过第 n 个节点x->next = x->next->next;// 返回新链表头return dummy->next;}// 辅助函数:找到倒数第 n 个节点ListNode* findFromEnd(ListNode* head, int n){ListNode* p1 = head;// 先让 p1 向前走 n 步for(int i = 0; i < n; ++i){p1 = p1->next;}// 然后让 p1 和 p2 一起走ListNode* p2 = head;while(p1 != nullptr){p1 = p1->next;p2 = p2->next;}// p2 就是倒数第 n 个节点return p2;}
};
四、时间复杂度分析
操作 | 复杂度 |
---|---|
单次遍历链表 | O(L),L 是链表长度 |
空间复杂度 | O(1),只使用了两个指针 |
所以这是一个 时间 O(n)、空间 O(1) 的解法。