给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。(说明给定的 n 保证是有效的。)
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
方法一:使用栈来存储
思路:时间复杂度O(n),空间复杂度O(n)
【1】压栈处理,将所有结点存入vector容器。
【2】之后进行for循环出栈,并跳过第n个结点
ListNode* removeNthFromEnd(ListNode* head, int n) {
vector<ListNode*> vec;
int length = 0;
while (head != NULL) {
vec.push_back(head);
head = head->next;
++length;
}
ListNode* dummyHead = new ListNode(-1); //假的头结点
ListNode* p = dummyHead;
for (int i = 0;i < vec.size();++i) {
if (i != length - n) { //倒数第n个结点
p->next = vec[i];
p = p->next;
}
}
p->next = NULL; //将最后一个结点next置空
return dummyHead->next;
}
方法二:双指针,减小空间复杂度
思路:找到第n个结点的前一个结点,即倒数第n+1个结点。时间复杂度O(n),空间复杂度O(1)
【1】使用两个指针(p,pre)开始都指向头节点。然后p先往后走n+1步
【2】之后p,pre同步往后走,当p走到NULL时,pre就为倒数第n+1个结点
【3】若p走到NULL时,步数小于n+1,则n超出链表的长度。
ListNode* removeNthFromEnd(ListNode* head, int n) {
//找到倒数第n+1个结点
ListNode *p = head;
ListNode *pre = head; //倒数第n+1个结点
int step = n + 1;
while (p != NULL)
{
//当step为0时,p,pre同步走
if (step == 0) {
pre = pre->next;
p = p->next;
}
else { //p先开始走n+1步
p = p->next;
--step;
}
}
//删除头节点
if (step > 0) {
pre = head->next;
free(head);
return pre;
}
else {
ListNode *temp = pre->next;
pre->next = temp->next;
free(temp);
return head;
}
}