题目:https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/submissions/
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
进阶:你能尝试使用一趟扫描实现吗?
我的方法一:遍历两遍
步骤
- 先遍历一遍,得出链表的长度
- 根据长度和倒数第几个,计算出要删除的点是第几个
- 根据计算出的位置,找到这个点,删除即可
边界条件
- 当长度小于n时,说明要删除的点不存在,不需要做什么,直接返回head即可。
- 当长度等于n时,说明要删除的是头节点;
代码
/**
* 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) {
int list_size = 0;
ListNode* cur = head;
while(cur) {
list_size++;
cur = cur->next;
}
if(list_size < n) {
return head;
}else if(list_size == n) {
return head->next;
}
int index = list_size - n;
ListNode* pre = nullptr;
cur = head;
while(index > 0) {
pre = cur;
cur = cur->next;
index--;
}
pre->next = cur->next;
return head;
}
};
我的方法二:遍历一遍
步骤
- 设置一个最大长度是n的队列
- 遍历链表,并将遍历到的节点push到队列,当队列长度超过n时,那么将队列的头节点pop出,并记下这个pop出的节点
- 直到遍历完,那么队列的头节点就是要删除的节点;
边界条件
- 如果队列最终的长度小于n,那么说明链表长度小于n,所以不需要删除
- 当最近pop出的节点为空,说明倒数第n个节点就是头节点,所以直接返回head->next即可
代码
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
if(n <= 0) {
return head;
}
queue<ListNode*> q;
ListNode* last_poped = nullptr;
ListNode* cur = head;
while(cur) {
q.push(cur);
if(q.size() > n) {
last_poped = q.front();
q.pop();
}
cur = cur->next;
}
if(q.size() < n) {
return head;
}
if(last_poped) {
last_poped->next = q.front()->next;
return head;
}else{
return q.front()->next;
}
}
};
其他方法
使用栈
- 将所有的节点都压入栈中
- 然后pop,pop到的第n个就是要删除的。
缺点就是栈的长度和原始链表的长度一样,所以空间复杂度是O(n),而队列的空间复杂度是O(1)