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?
第一次错误代码
/**
* 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) {
int l=0;
ListNode* p=head;
while(p)
{
l++;
p=p->next;
}
int index=1;
p=head;
while(p)//当删除第一个节点时无法实现
{
if(index==l-n)
p->next=p->next->next;
p=p->next;
index++;
}
return head;
}
};
第二次通过代码
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
int l=0;
ListNode* p=head;
while(p)
{
l++;
p=p->next;
}
ListNode* ans=new ListNode(0);//建立头结点,与head链接起来
int index=0;//index现表示头结点的下标
ans->next=head;
p=ans;
while(index!=l-n)
{
p=p->next;
index++;
}//找到待删除结点的前一个结点p
p->next=p->next->next;//删除该节点
return ans->next;
}
};
如果结果可能为空,应该加个头结点,然后返回头结点的next。此方法是两次遍历,先找到链表长度,再遍历删除,遍历操作执行了2L-n步。
题目说Could you do this in one pass?
好的,来看看官方一次遍历解法
我们可以使用两个指针而不是一个指针。第一个指针从列表的开头向前移动 n+1步,而第二个指针将从列表的开头出发。现在,这两个指针被 n 个结点分开。我们通过同时移动两个指针向前来保持这个恒定的间隔,直到第一个指针到达最后一个结点。此时第二个指针将指向从最后一个结点数起的第 n 个结点。我们重新链接第二个指针所引用的结点的 next 指针指向该结点的下下个结点。
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* ans=new ListNode(0);
ans->next=head;
ListNode* p,*q;
p=ans;
q=ans;
int pt,qt;
pt=0;
qt=0;
while(q)//q为空即指向尾结点的next
{
if(qt-pt<=n)//p,q中结点个数小于n,p向后移动,q保持不变
{
q=q->next;
qt++;
}
else//p,q同时向后移
{
p=p->next;
q=q->next;
pt++;
qt++;
}
}
//删除q后面的结点
p->next=p->next->next;
return ans->next;
}
};