原题描述
+
给定一个链表,删除链表的倒数第n个节点,并且返回链表的头结点,题目给定的 n 保证是有效的。你能尝试使用一趟扫描实现吗?
示例
输入:list=[1,2,3,4,5], n=2
输出:[1,2,3,5]
原题链接:https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list
思路解析
+
记得找工作那时候刷题有两道入门级的题目印象深刻,一道题是找出链表是否有环,另一个就是这道题。
一趟扫描的思路是非常容易想到的。因为你知道要删除的节点距离末尾隔着n个节点,所以你只借助两个同时移动,但距离始终保持为n的指针就可以轻松实现。当前面的指针跑到结尾的时候,后面指针停留的位置恰好就是倒数第n个节点。
虽然思路非常简单,但是很少人能够在短时间内调通,因为面对的边界条件其实是有点讨厌的。所以凡是链表的题目,我都会加一个哑结点(头节点),这样可以方便处理任何case。
复杂度分析
+
计算步骤
+
1. 首先添加哑结点dummy,同时p指针和q指针都指向dummy;

2. 先让第一个指针q移动n步;

3. 同时移动指针p和q,直到q指向末尾(NULL);

最后一定要记得把哑结点和p指向的节点删掉。
C++参考代码
+
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode *dummy = new ListNode(-1);
dummy->next = head;
ListNode *p = dummy, *q = dummy;
while (n) { q = q->next; --n; }
while (q->next != NULL) {
p = p->next;
q = q->next;
}
ListNode *rm = p->next;
p->next = p->next->next;
head = dummy->next;
delete(rm);
delete(dummy);
return head;
}
};