这题中等难度,但是感觉好像并不难。
如果想要一次遍历链表就可能比较困难了,先正常解法:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n)
{
ListNode*dummy=new ListNode(0);
dummy->next=head;
ListNode*pFind=dummy;
int count=0;
while(pFind->next)
{
count++;
pFind=pFind->next;
}
pFind=dummy;
for(int i=0;i<count-n;i++)
{
pFind=pFind->next;
}
pFind->next=pFind->next->next;
return dummy->next;
}
};
两次遍历的目的是:在第一次遍历中我们可以得到链表的长度,这样方便下一次寻找目标结点。
一次遍历就无法知道链表的长度,换种思维,
我们可以从尾部开始,寻找特征。
比如,倒数第一个,其下一个指针指向null,即cur->next=nullptr
倒数第二个,其下两个指针指向null,即cur->next->next=nullptr
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n)
{
ListNode*dummy=new ListNode(0);
dummy->next=head;
ListNode*pFirst=dummy->next;
ListNode*pSlow=dummy->next;
for(int i=1;i<n+1;i++)
{
pFirst=pFirst->next;
}
while(pFirst->next)
{
pFirst=pFirst->next;
pSlow=pSlow->next;
}
pSlow->next=pFirst;
return dummy->next;
}
};
结果报错!!说是使用了空指针!
即 while(pFirst->next)
题目给的例子是 【1】 1
于是,又重新理了一遍,发现这种情况下,
当pFirst->next=nullptr不执行时,pFirst=pSlow,此时
pSlow->next=pFirst 这句话就显得有点怪了
看了一下答案,稍微变化了一下
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n)
{
ListNode*dummy=new ListNode(0);
dummy->next=head;
ListNode*pFirst=dummy->next;
ListNode*pSlow=dummy;
for(int i=0;i<n;i++)
{
pFirst=pFirst->next;
}
while(pFirst)
{
pFirst=pFirst->next;
pSlow=pSlow->next;
}
pSlow->next=pSlow->next->next;
return dummy->next;
}
};