题目
分析
最近在把之前刷过的LC题目拿出来重做,选一些经典的题目记录下来,这道题就是很经典的也适合面试的时候写的题。
这道题不难,但是链表的题目就是需要注意一些边界情况。所以一般链表的题目在写代码的时候有两个注意的点:
- 一般都会手动加一个头结点来方便对第一个结点的处理。
- 一般在修改指针的next的时候需要考虑这个指针是否为空 即考虑是否需要&& p
下面来看这道题,最优的做法就是扫描一遍,我们定义一个cur指针和pre指针,cur指针是我们的遍历指针,pre指针是我们记录用来做修改的指针。这题的关键就是要找到pre的合适位置,以图中例子为例,pre的合适位置在3,为什么是3,因为找到3就只需要将3的next的next赋值给3的netx就完成了删除。那怎么找到3呢,我们看这个例子n恰好是2,所以我们只需要用两个指针pre和cur,一快(cur)一慢(pre),快指针先走n步,然后和慢指针同步走,当快指针走到最后一个结点的时候,慢指针就恰好是我们需要的位置。
代码
/**
* 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), *cur = dummy, *pre = dummy;
dummy->next = head;
// 快指针先走n步
while (cur && n--) {
cur = cur->next;
}
// 其实这里原本是需要判断n是否大于0 如果大于0就说明要删除的结点实际不存在 但是题目保证了n是有效的
// 注意在写cur->next之前需要保证cur不空
while (cur && cur->next) {
cur = cur->next;
pre = pre->next;
}
pre->next = pre->next->next;
return dummy->next;
}
};