题目:给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
1.题解1(双指针):
思路:题目给出的链表是没有哑结点的,为了不单独讨论头结点的删除。我们可以手动new一个哑结点。
另外,我们可以设置两个指针p1和p2。两个指针都是从哑结点开始,p2先走n-1步,此时两个结点的距离就是n-1,有n个结点。然后,再让p1和p2两个指针一起走,直到p2到达末尾,此时p1所指向的结点就是倒数第n个结点了。(因为p1和p2的距离正好隔着n-1)。
Tip:注意delete相关结点,及时清理内存。(虽然在做题时程序结束就会自动清楚,但是要养成好习惯)。但是我们删除内存以后,其实这个指针还是会指向该结点,因此我们一般将该指针还要置为NULL(C++)中空指针并没有害。
另外,最后不能直接返回head,如果直接删除的是head的话,return head就会出现错误,因为head这个结点已经不属于该链表了。因此可以return dummynode->next。但是如果要删除dummynode所占的内存,则可以令ans=dummynode->next,然后return ans。
/**
* 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) {
//由于题目本身并没有提供哑结点,因此最好我们new一个哑结点,方便删除第一个结点的情况
ListNode* dummynode=new ListNode(-1);
ListNode *p1,*p2,*p3;
dummynode->next=head;
p1=p2=dummynode;
for(int i=0;i<n;i++)
p2=p2->next;
while(p2->next!=NULL)
{
p1=p1->next;
p2=p2->next;
}
p3=p1->next;
p1->next=p1->next->next;
delete p3;
return dummynode->next;
}
};
题解2(栈):
思路:栈是一种后进先出的结构,因此可以将链表全部压入栈中,然后第n个pop的元素正好是倒数第n个元素,此时的top()就是要删除的结点的前一个结点。
/**
* 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) {
stack<ListNode*> s;
ListNode* ans,*p;
ListNode* dummynode=new ListNode(0,head);
p=dummynode;
while(p!=NULL)
{
s.push(p);
p=p->next;
}
for(int i=0;i<n;i++)
{
s.pop();
}
s.top()->next=s.top()->next->next;
ans=dummynode->next;
delete dummynode;
return ans;
}
};