目录
题目
19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)
解法一
双指针算法
核心思想
利用双指针间隔固定距离(n+1),当快指针到达链表末尾时,慢指针恰好位于倒数第n个节点的前一位置。
执行流程
- 创建哑节点dummy,指向链表头部
- 初始化快指针fast和慢指针slow,都指向dummy
- fast先前进n+1步
- fast和slow同时前进,直到fast到达NULL
- slow此时指向待删除节点的前一节点,执行删除操作
- 返回dummy->next作为新的头节点
具体例子
对于链表1→2→3→4→5,删除倒数第2个节点(n=2):
- 创建dummy→1→2→3→4→5
- fast和slow初始都指向dummy
- fast前进3步(n+1):fast指向3
- fast和slow同时前进:
- 当fast到达5后的NULL
- slow指向3
- 删除slow->next(即4):3→5
- 返回dummy->next:1→2→3→5
代码
cpp
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummy = new ListNode(0);
dummy->next = head;
ListNode* fast = dummy;
ListNode* slow = dummy;
for(int i = 0; i<n+1; i++)
{
if(!fast)
{
return head;
}
fast = fast->next;
}
while(fast)
{
fast = fast->next;
slow = slow->next;
}
if(slow->next)
{
ListNode* toDelete = slow->next;
slow->next = slow->next->next;
delete toDelete;
}
ListNode* newhead = dummy->next;
delete dummy;
return newhead;
}
};
解法二
两次遍历法
核心思想
执行流程
- 创建哑节点dummy,指向链表头部
- 第一次遍历计算链表长度length
- 计算待删除节点的正序位置:position = length - n
- 第二次遍历,前进position步找到待删除节点的前驱
- 删除目标节点
- 返回dummy->next作为新的头节点
具体例子
对于链表1→2→3→4→5,删除倒数第2个节点(n=2):
- 创建dummy→1→2→3→4→5
- 计算链表长度length = 5
- 找到正序位置:position = 5 - 2 = 3
- 从dummy开始前进3步到达节点3
- 删除节点3的下一个节点(4):3→5
- 返回dummy->next:1→2→3→5
双指针法效率更高,因为只需一次遍历;两次遍历法思路更直观,易于理解。
代码
cpp
ListNode* removeNthFromEnd(ListNode* head, int n) {
// 创建哑节点
ListNode* dummy = new ListNode(0);
dummy->next = head;
// 第一次遍历计算链表长度
int length = 0;
ListNode* first = head;
while (first) {
length++;
first = first->next;
}
// 计算要删除节点的位置
int position = length - n;
// 找到待删除节点的前一个节点
ListNode* curr = dummy;
for (int i = 0; i < position; i++) {
curr = curr->next;
}
// 删除节点并释放内存
ListNode* toDelete = curr->next;
curr->next = curr->next->next;
delete toDelete;
// 获取新的头节点
head = dummy->next;
delete dummy;
return head;
}