提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
删除链表倒数第N个节点,直观想到的是遍历两次。为了节约运行时间,题目提示了能否遍历一次完成。因而以下做法都只涉及遍历一次链表。对于链表操作,有一个**小技巧**。通常在head前加一个哑元,避免对头节点的特判。一、问题概要
二、解法
1.vector实现
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
/* 使程序更鲁棒 */
if(!head)return head;
if(n <= 0)return head;
ListNode* dummy = new ListNode();
dummy -> next = head;
vector<ListNode*> nodes;
/* 指针遍历链表 */
ListNode* path = dummy;
while(path != nullptr){
nodes.emplace_back(path);
path = path -> next;
}
int amounts = nodes.size();
/* 找到要删除节点的前一个结点 */
if(amounts - 1 - n >= 0){
nodes[amounts - 1 - n] -> next = nodes[amounts - n] -> next;
}
return dummy -> next;
}
};
时间复杂度O(n)
空间复杂度O(n)
n 为链表长度
2. 双指针实现
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
/* 使程序更鲁棒 */
if(!head)return head;
if(n <= 0)return head;
ListNode* dummy = new ListNode();
dummy -> next = head;
/* 指针遍历链表 */
ListNode* first = dummy;
ListNode* second = dummy;
/* second 节点领先n个节点 */
/* second 节点到达尾部时,first节点恰好为要删除节点的前一个节点 */
for(int i = 0;i < n && second -> next != nullptr;i++){
second = second -> next;
}
if(second -> next != nullptr){
while(second -> next != nullptr){
first = first -> next;
second = second -> next;
}
}
first -> next = first -> next -> next;
return dummy -> next;
}
};
时间复杂度O(n)
空间复杂度O(1)
n 为链表长度
总结
每次写哑元都有一种艺术感。另外双指针法是一种常用的方法,希望你掌握了。
最后,一看三连是个好习惯。欢迎评论区讨论●ω●