给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
解题思路:第一种,设置qp两个指针同时指向head,然后先让p指针向后移动,并在移动n次后,让q指针也开始向后移动,这样q和p之间的距离为n,当p到达尾结点时,q指针也刚好到达了倒数第n个节点,然后进行逻辑删除,代码如下:
```cpp
/**
* 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* newlist = new ListNode(NULL);
newlist->next=head;//要用于作为返回值
ListNode* q=newlist;
ListNode* p=newlist;
int d=0;
while(p->next!=NULL){
if(d<n){//因为pq之间保持n的距离,这样p到尾结点时q刚好到倒数第n个
p=p->next;
d++;
}
else{
p=p->next;
q=q->next;
}
}
q->next=q->next->next;//从逻辑上删除了倒数第n个
return newlist->next;
}
};
```
第二种思路:先让p指针向后移动,并以d作为移动的次数,这样p移动到末尾后,开始移动q,移动d-n次说明q已经移动到了倒数第n个,然后对此处进行逻辑删除
```cpp
/**
* 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* newlist = new ListNode(NULL);
newlist->next=head;//要用于作为返回值
ListNode* q=newlist;
ListNode* p=newlist;
int d=0,i=0;
while(p->next!=NULL){
p=p->next;
d++;//d是链表的长度
}
while(q!=NULL && i!=d-n){//链表中的循环判断条件中必须要判断指针是否指向了一个有意义的位置
//i是向前推进的次数,当推进到d-n次时已经到达倒数第n个
q=q->next;
i++;
}
q->next=q->next->next;
return newlist->next;
}
};
```
第三种代码如下:
```cpp
class Solution {
public:
int length(ListNode *head){
int i=0;
auto a=head;
while(a!=NULL){
a=a->next;
i++;
}
return i;
}
ListNode* removeNthFromEnd(ListNode* head, int n) {
if(head==NULL){
return head;
}
auto p=head;;
int lengthA;
int i=0;
lengthA=length(head);
if(n>=lengthA){
head=head->next;
}
else{
while(i<lengthA-n-1 && p!=NULL){
p=p->next;
i++;
}
p->next=p->next->next;
}
return head;
}
};
```