问题描述:
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
解法一:
扫描两遍,第一遍知道长度,第二遍就可以删除倒数第N个结点。
解法二:
使用两个指针,快慢指针法。快指针先移动n个节点,然后再和慢指针一起移动,直到快指针到NULL,至此,慢指针就找到倒数第n各节点。
可以加一个“哑结点”指向头结点。
贴一个大佬的动画图解:
作者:MisterBooo
链接:https://leetcode-cn.com/problems/two-sum/solution/dong-hua-tu-jie-leetcode-di-19-hao-wen-ti-shan-chu/
/**
* 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(0);//哑结点
dummy->next = head;
ListNode *fast=dummy;
ListNode *slow=dummy;
for(int i=0; i < n ; i++){
fast = fast -> next;
}
while(fast->next != NULL){
fast = fast -> next;
slow = slow -> next;
}
//此时slow指针指向的是倒数第n各节点的前一个节点
slow->next = (slow->next) ->next;
return dummy->next;
}
};
解法三:
使用递归的方法进行一次扫描,才退出递归栈的时候删除倒数第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) {
if(n==1){//要删除最后一个 (head -> next) -> next==NULL
ListNode *temp = head;
while( (temp -> next)->next != NULL){
temp=temp->next;
}
temp->next=NULL;
return head;
}
scan(head,n);
return head;
}
void scan(ListNode* head, int n){
static int count = 0;
while(head -> next != NULL){
scan(head -> next,n);
count++;
if(count == n ){//找到倒数第N+1个结点,方便删除
if(head->next != NULL ){
int val_next = (head->next) -> val;
ListNode *temp_next = (head->next) ->next;
head->val = val_next;
head->next= temp_next;
temp_next = NULL;
}
}
return ;
}
count++;
return ;
}
};