Given a linked list, remove the n-th node from the end of list and return its head.
Example:
Given linked list: 1->2->3->4->5, and n = 2. After removing the second node from the end, the linked list becomes 1->2->3->5.
Note:
Given n will always be valid.
Follow up:
Could you do this in one pass?
此题类似于求解链表的倒数第n个节点。分析如下
(图示一)同样是使用两个指针来获得链表的倒数第n个节点,但我们这个题目是要删除倒数第n个节点,所以使用pPre指针指向欲删除节点的前一个节点。这样最终我们得到欲删除节点的前一处(pPre)位置时,使 pPre->next 指向 pPre->next->next (欲删除节点的下一个节点),即跳过欲删除节点。
(图示二)注意到此题是返回删除后的链表,return为链表的头节点。而头节点也可能被删除。所以当pAhead指向为空时说明n等于链表长度,即欲删除节点为头节点,此时返回head->next即可。
之前做删除节点时,使用的是“狸猫换太子”,将欲删除节点的值换为后一个节点的值,再跳过后一个节点。而此题我们可以轻易得到与删除节点的上一个节点,所以直接在上一个节点进行跳过欲删除节点即可。
pPre指针指向欲删除节点的前一个节点,所以在pAhead先走时,可以先走一步,这样后面同时移动后,pPre就是倒数第n个节点的上一个节点了。
ListNode* removeNthFromEnd(ListNode* head, int n) {
if(head == nullptr)
return nullptr;
if(n<=0) // n输入非法
return head;
ListNode* pPre = head; // 倒数第n个节点的前一个,方便进行删除操作
ListNode* pAhead = head; // 先行节点
for(int i=0; i<n; i++) { // 正常应该少移动一位,但是这里我们欲得到pPre为删除节点的前一个节点
pAhead = pAhead->next;
}
if(pAhead == nullptr) // n=链表长度,此时删除的是头节点
return head->next;
while(pAhead->next != nullptr) { // pPre和pAhead同时移动
pPre = pPre->next;
pAhead = pAhead->next;
}
pPre->next = pPre->next->next; // 跳过pPre->next(要删除的节点)
return head;
}