19. Remove Nth Node From End of List[M]删除链表的倒数第N个节点
题目
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?
思路
思路一:Two Pass
首先定义一个辅助节点auxList,使它的下一个节点指向链表head,用来简化边界判断的条件,例如一个链表只有一个节点,删除了头节点。第一次遍历(one pass),得到链表的长度L;第二次遍历(two pass)设置一个指针指向辅助节点auxList,并开始删除节点,一直到指定的n停止,此时到达第\(L-n\)个节点;将第\(L-n\)与第\(L-n+2\)个节点重新连接,于是就删除了第\(L-n+1\)个节点(因为人为增加一个节点)。
思路二:One Pass
题目让我们思考,如何通过一次循环来实现对链表倒数N个节点的删除。
- 双指针法
可以利用双指针法来解决倒数的问题:- 第一个指针快一点,用来控制循环的次数
- 第二个指针慢一点,用于遍历
两个指针都是指向链表,也就是两个指针对应两个一样的链表。要想一次遍历实现对第\(L-n\)个节点的删除,首先用第一个指针“跑”完n次,此时第二个指针开始“跑”,并且以第一个指针从第n个节点跑到第L-1个节点为循环次数,此时相当于第二个链表跑了\(L-n\)个数,这样就找到了链表中倒数第n个数。
- 递归
这种涉及单链表的插入与删除都可以考虑递归,因为插入和删除都要涉及到上一层节点的操作。将最后一个节点设置为第一层,逐层f返回,当返回到第n+1层开始删除。
Tips
单链表
链表的删除
length -= n;
pass = auxList;
while(length > 0){
length --;
pass = pass->next;
}
pass->next = pass->next->next;
return auxList->next; //这里返回next是因为auxList的next才是原来的链表
}
* 思路二(1)
```cpp
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* auxList = new ListNode(0);
auxList->next = head;
ListNode* point1 = auxList;
ListNode* point2 = auxList;
for(int i = 1; i <= n + 1;i++)
point1 = point1->next;
while(point1 != NULL){
point1 = point1->next;
point2 = point2->next;
}
point2->next = point2->next->next;
return auxList->next;
}
- 思路二(2)
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* auxList = new ListNode(0);
auxList->next = head;
remove(auxList, n);
return auxList->next;
}
int remove(ListNode* head, int n){
if(head->next == NULL)
return 1;
int levels = remove(head->next, n) + 1;
if(levels == n+1)
head->next = head->next->next;
return levels;
}
Python
参考
[1] 算法导论第10章10.2,p131
[2] http://www.cnblogs.com/skywang12345/p/3561803.html