##力扣刷题之删除链表倒数第n个节点
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗
来源:力扣(LeetCode)
struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
struct ListNode *Head=head;
struct ListNode *aimNode=NULL;
int m;
int size=0; //链表长度
if(head->next==NULL){
return Head->next;
}
for(head;head!=NULL;head=head->next,size=size+1){
}
head=Head;
m=size-n;
if(m==0) //删除头结点
{
Head=Head->next;
return Head;
}
if(n==1){ //删除最后一个节点
for(head;head->next->next!=NULL;head=head->next){
}
head->next=NULL;
return Head;
}
for(int i=0;i<m-1;i++){
head=head->next;
}
head->next=head->next->next;
return Head;
}
解题思想:
没考虑只用一次便利就解决问题,首先使用的是比较传统的思想,先编译一遍链表,得到链表的长度size,然后利用所得长度减去n得到需要删去的节点,得到需要删除节点的前一个节点操作必要容易,所以遍历的时候只遍历到前一个节点,然后对链表进行操作。
注意:
在代码实现的过程中,遇到两种特殊情况需要处理。
1.删除头结点的情况。
2.删除最后一个节点。
代码2:
struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
struct ListNode *first=NULL;
struct ListNode *second=NULL;
struct ListNode *thead=malloc(sizeof(struct ListNode));
thead->val=0;thead->next=head;
first=head;second=thead;
for(int i=0;i<n;i++){
first=first->next;
}
while(first){
first=first->next;
second=second->next;
}
second->next=second->next->next;
struct ListNode *ans=thead->next;
free(thead);
return ans;
}
解题思想2:
看过题解后,知道了只需要一次遍历就能解题的解题思想。
利用快慢指针first和second,先让first遍历n次,再让second开始遍历,这样
first和second之间相隔n-1个节点,first和second就相差n,当first遍历到链表结尾的时候,second就刚好到需要删除的节点。
注意:
1.让second遍历到需要删除的节点的前一个节点更好操作,所以可以让增加一个空节点其next指向头节点,second开始指向这个节点即thead->next=head,second=thead;这样当first指向链表结尾的时候,second指向需要删除节点的前一个节点。但是不要让first多遍历一次,这样在某些情况时会导致first遍历到尾结->next->next,导致报错。
2.考虑删除头节点的情况。