给你一个链表,删除链表的倒数第 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]
实现代码:
下面我会介绍四种方法。
计算链表长度法
class Solution {
public:
//求链表的长度
int getLength(ListNode* head) {
int length = 0;
while (head)
{
++length;
head = head->next;
}
return length;
}
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummyhead = new ListNode(0);
dummyhead->next=head;
int length = getLength(head);
ListNode* cur = dummyhead;
for (int i = 1; i < length - n + 1; ++i) {
cur = cur->next;
}
ListNode* temp=cur->next;
cur->next = cur->next->next;
delete temp;
return dummyhead->next;;
}
};
没什么可说的,就是直接算出链表长度后,找到位置然后删除,算是此题最暴力最简单的解法了,不过相当于扫描了两趟,就不符合进阶里描述的用一趟来实现了。所以还是推荐用下面的方法,写起来相对又快又方便。
-
时间复杂度:O(L)
-
空间复杂度:O(1)
双指针法
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n)
{
ListNode* dummyhead=new ListNode(0);//新头节点
dummyhead->next=head;
ListNode* fast=dummyhead;//快指针
ListNode* slow=dummyhead;//慢指针
n++;
while(n--&&fast!=NULL)
{
fast=fast->next;
}
while(fast!=NULL)
{
fast=fast->next;
slow=slow->next;
}
ListNode* temp=slow->next;
slow->next=slow->next->next;
delete temp;
return dummyhead->next;
}
};
原理就是快指针先移动n次,然后快慢指针一起移动,在快指针指到链表末尾时,慢指针就走到了所要删除的结点,这里我们删除结点需要让慢指针指向所需删除结点的前驱结点,所以我们先让n++,这样就可以了。
-
时间复杂度:O(L)
-
空间复杂度:O(1)
递归法
class Solution {
public:
int count=0;//计数
ListNode* removeNthFromEnd(ListNode* head, int n)
{
if(head==NULL)
{
return head;
}
head->next=removeNthFromEnd(head->next,n);
count++;//每返回一次就加一
if(count==n)
{
return head->next;//返回head->next
delete head;
}
return head;
}
};
我刚看到题目时,就想到用递归法,因为要倒着计数,然后删除。相对理解起来也很简单,就是每此返回后count就加一,当count=n时,直接返回当前结点的后一个结点就可完成删除操作。
-
时间复杂度:O(L)
-
空间复杂度:O(L)
利用栈法
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n)
{
ListNode* dummyhead=new ListNode(0);//创建一个新的头结点
dummyhead->next=head;
stack<ListNode*> stk;
ListNode* cur=dummyhead;
while(cur)
{
stk.push(cur);
cur=cur->next;
}
for(int i=0;i<n;i++)
{
stk.pop();
}
ListNode* pre=stk.top();//获取目标节点的前驱结点
ListNode* temp=pre->next;
pre->next=pre->next->next;
delete temp;
return dummyhead->next;
}
};
先将链表全部结点入栈,然后出栈,这样就可以倒着计数,和递归一个思路,毕竟递归就是利用栈来完成的,这里就不细说了,看一下就懂了。
-
时间复杂度:O(L)
-
空间复杂度:O(L)