题目描述
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
示例 1:
输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]
示例 2:
输入:head = [1], n = 1
输出:[]
示例 3:
输入:head = [1,2], n = 1
输出:[1]
进阶: 你能尝试使用一趟扫描实现吗?
解题思路
1.遍历两次,第一次记录倒数第N个位置在链表中的正序的位置。但是遍历了两次链表。
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode *p=head;
ListNode *r=head;
int i=0;
while(p){//记录总的链表长度
i++;
p=p->next;
}
if(i==n){//特殊情况 删除倒数的元素就是正序的第一个元素
head=head->next;
return head;
}
int j=i-n,k=1;// 倒数第N个元素在正序中第j个位置
while(k<j){
r=r->next;
k++;
}
p=r->next;//直接进行覆盖
r->next=p->next;
return head;
}
2.利用快慢指针(双指针)遍历,先用快指针先前进N个节点,然后快和慢指针一起移动,直到快指针遍历到最后一个节点,此时的慢指针就是倒数第N+1个节点。
N + X =Length
// N就是快指针一开始走自己的步数,X表示后面快慢指针一起走的步数。
//慢指针只走了X步,还有N步没有走完,也就是走到了倒数第N+1个节点。
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode *pre=new ListNode(0);//设置一个虚节点
pre->next=head;
ListNode* fast=pre;//快指针
ListNode* slow=pre;//慢指针
while(n--){//先让快指针走N步
fast=fast->next;
}
while(fast->next){//快慢指针一起走
slow=slow->next;
fast=fast->next;
}
ListNode* tmp=slow->next;//养成一个好习惯释放节点
slow->next=slow->next->next;
delete tmp;//养成一个好习惯释放节点
return pre->next;//注意返回的表示
}
别看上面有两个while就是遍历了两次,仔细看快指针只遍历了一次,当然也可以放在一个while里,写的目的是方便读者理解。